aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilia Kasper <ekasper@google.com>2016-10-14 15:58:23 +0200
committerThai Duong <thaidn@google.com>2016-11-30 17:59:14 -0800
commitf7ecb0dfad2cc15d42eacefb13e8675dd664dd38 (patch)
tree3cc36a764b92a450d5439eafd03f951fc06dcbc4
parentc662a0ac9004a20276345d39d2ce1cfca16eb8a8 (diff)
downloadwycheproof-f7ecb0dfad2cc15d42eacefb13e8675dd664dd38.tar.gz
Initial GitHub export
-rw-r--r--.gitignore1
-rw-r--r--BUILD106
-rw-r--r--CONTRIBUTING43
-rw-r--r--LICENSE202
-rw-r--r--README.md140
-rw-r--r--WORKSPACE99
-rw-r--r--build_defs.bzl119
-rw-r--r--doc/bugs.md5
-rw-r--r--doc/dh.md141
-rw-r--r--doc/dsa.md192
-rw-r--r--doc/ecdh.md58
-rw-r--r--doc/index.md80
-rw-r--r--doc/rsa.md130
-rw-r--r--java/com/google/security/wycheproof/BouncyCastleAllTests.java53
-rw-r--r--java/com/google/security/wycheproof/BouncyCastleTest.java55
-rw-r--r--java/com/google/security/wycheproof/ConscryptTest.java51
-rw-r--r--java/com/google/security/wycheproof/EcUtil.java454
-rw-r--r--java/com/google/security/wycheproof/OpenJDKAllTests.java34
-rw-r--r--java/com/google/security/wycheproof/OpenJDKTest.java36
-rw-r--r--java/com/google/security/wycheproof/ProviderIndependentTest.java26
-rw-r--r--java/com/google/security/wycheproof/RandomUtil.java185
-rw-r--r--java/com/google/security/wycheproof/SpongyCastleAllTests.java54
-rw-r--r--java/com/google/security/wycheproof/SpongyCastleTest.java56
-rw-r--r--java/com/google/security/wycheproof/TestUtil.java99
-rw-r--r--java/com/google/security/wycheproof/WycheproofRunner.java206
-rw-r--r--java/com/google/security/wycheproof/testcases/AesEaxTest.java268
-rw-r--r--java/com/google/security/wycheproof/testcases/AesGcmTest.java405
-rw-r--r--java/com/google/security/wycheproof/testcases/BasicTest.java45
-rw-r--r--java/com/google/security/wycheproof/testcases/BigIntegerTest.java461
-rw-r--r--java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java279
-rw-r--r--java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java239
-rw-r--r--java/com/google/security/wycheproof/testcases/DhTest.java396
-rw-r--r--java/com/google/security/wycheproof/testcases/DhiesTest.java157
-rw-r--r--java/com/google/security/wycheproof/testcases/DsaTest.java655
-rw-r--r--java/com/google/security/wycheproof/testcases/EcKeyTest.java230
-rw-r--r--java/com/google/security/wycheproof/testcases/EcdhTest.java1125
-rw-r--r--java/com/google/security/wycheproof/testcases/EcdsaTest.java462
-rw-r--r--java/com/google/security/wycheproof/testcases/EciesTest.java347
-rw-r--r--java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java138
-rw-r--r--java/com/google/security/wycheproof/testcases/RsaKeyTest.java139
-rw-r--r--java/com/google/security/wycheproof/testcases/RsaSignatureTest.java140
41 files changed, 8110 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ac51a05
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+bazel-*
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..a47d747
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,106 @@
+# Wycheproof tests
+
+java_library(
+ name = "utils",
+ srcs = [
+ "java/com/google/security/wycheproof/EcUtil.java",
+ "java/com/google/security/wycheproof/RandomUtil.java",
+ "java/com/google/security/wycheproof/TestUtil.java",
+ ],
+)
+
+common_deps = [
+ ":utils",
+]
+
+test_srcs = glob(["java/com/google/security/wycheproof/testcases/*.java"]) + ["java/com/google/security/wycheproof/WycheproofRunner.java"]
+
+# These targets run all tests.
+
+load(":build_defs.bzl", "bouncycastle_all_tests", "spongycastle_all_tests")
+
+# Generates BouncyCastleAllTests_1_xx target for all available versions,
+# plus a BouncyCastleAllTests alias for latest stable.
+#
+# To test latest stable:
+# $ bazel test BouncyCastleAllTests
+#
+# To test other versions, e.g., v1.52:
+# $ bazel test BouncyCastleAllTests_1_52
+#
+# To test all known versions (warning, will take a long time):
+# $ bazel test BouncyCastleAllTest_*
+bouncycastle_all_tests(
+ # This test takes a long time, because key generation for DSA and DH generate new parameters.
+ size = "large",
+ srcs = ["java/com/google/security/wycheproof/BouncyCastleAllTests.java"] + test_srcs,
+ test_class = "com.google.security.wycheproof.BouncyCastleAllTests",
+ deps = common_deps,
+)
+
+# Generates SpongyCastleAllTests_1_xx target for all available versions,
+# plus a SpongyCastleAllTests alias for latest stable.
+#
+# To test latest stable:
+# $ bazel test SpongyCastleAllTests
+#
+# To test other versions, e.g., v1.52.0.0:
+# $ bazel test SpongyCastleAllTests_1_52
+#
+# To test all known versions (warning, will take a long time):
+# $ bazel test SpongyCastleAllTests_*
+spongycastle_all_tests(
+ # This test takes a long time, because key generation for DSA and DH generate new parameters.
+ size = "large",
+ srcs = ["java/com/google/security/wycheproof/SpongyCastleAllTests.java"] + test_srcs,
+ test_class = "com.google.security.wycheproof.SpongyCastleAllTests",
+ deps = common_deps,
+)
+
+# These targets exclude slow tests.
+
+load(":build_defs.bzl", "bouncycastle_tests", "spongycastle_tests")
+
+# Generates BouncyCastleTest_1_xx target for all available versions,
+# plus a BouncyCastleTest alias for latest stable.
+#
+# To test latest stable:
+# $ bazel test BouncyCastleTest
+#
+# To test other versions, e.g., v1.52:
+# $ bazel test BouncyCastleTest_1_52
+#
+# To test all known versions:
+# $ bazel test BouncyCastleTest_*
+bouncycastle_tests(
+ size = "large",
+ srcs = ["java/com/google/security/wycheproof/BouncyCastleTest.java"] + test_srcs,
+ test_class = "com.google.security.wycheproof.BouncyCastleTest",
+ deps = common_deps,
+)
+
+# Generates SpongyCastleTest_1_xx target for all available versions,
+# plus a SpongyCastleTest alias for latest stable.
+#
+# To test latest stable:
+# $ bazel test SpongyCastleTest
+#
+# To test other versions, e.g., v1.52.0.0:
+# $ bazel test SpongyCastleTest_1_52
+#
+# To test all known versions:
+# $ bazel test SpongyCastleTest_*
+spongycastle_tests(
+ size = "large",
+ srcs = ["java/com/google/security/wycheproof/SpongyCastleTest.java"] + test_srcs,
+ test_class = "com.google.security.wycheproof.SpongyCastleTest",
+ deps = common_deps,
+)
+
+# Platform-independent tests
+java_test(
+ name = "ProviderIndependentTest",
+ size = "small",
+ srcs = ["java/com/google/security/wycheproof/ProviderIndependentTest.java"] + test_srcs,
+ deps = common_deps,
+)
diff --git a/CONTRIBUTING b/CONTRIBUTING
new file mode 100644
index 0000000..fa97ad3
--- /dev/null
+++ b/CONTRIBUTING
@@ -0,0 +1,43 @@
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement]
+(https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Disclosure
+If your tests uncover security vulnerabilities, please first report directly to
+the maintainers of the libraries. You should only submit tests to us once the
+bugs have been acknowledged or fixed.
+
+Google has several
+[security reward programs](https://www.google.com/about/appsecurity/programs-home/)
+that provide cash rewards for quality security research that identifies or fixes
+security vulnerabilities in products that we provide or proactive security
+improvements to select open-source products. If your tests found or helped fix
+vulnerabilities that are in scope you should submit them to these programs.
+
+If you have any question with regard to disclosure, please email us at
+security@google.com.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the
+[Software Grant and Corporate Contributor License Agreement]
+(https://cla.developers.google.com/about/google-corporate). \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/README.md b/README.md
index 8ae5d14..b27f45e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,139 @@
-Placeholder to init branch
+# Project Wycheproof
+https://github.com/google/wycheproof
+
+*Project Wycheproof is named after
+[Mount Wycheproof](https://en.wikipedia.org/wiki/Mount_Wycheproof), the smallest
+mountain in the world. The main motivation for the project is to have a goal
+that is achievable. The smaller the mountain the more likely it is to be able to
+climb it.*
+
+## Introduction
+
+Project Wycheproof tests crypto libraries against known attacks. It is developed
+and maintained by members of Google Security Team, but it is not an official
+Google product.
+
+At Google, we rely on many third party cryptographic software libraries.
+Unfortunately, in cryptography, subtle mistakes can have catastrophic
+consequences, and we found that libraries fall into such implementation
+pitfalls much too often and for much too long. Good implementation guidelines,
+however, are hard to come by: understanding how to implement cryptography
+securely requires digesting decades' worth of academic literature. We recognize
+that software engineers fix and prevent bugs with unit testing, and we found
+that cryptographic loopholes can be resolved by the same means.
+
+These observations have prompted us to develop Project Wycheproof, a collection
+of unit tests that detect known weaknesses or check for expected behaviors of
+some cryptographic algorithm. Project Wycheproof provides tests for most
+cryptographic algorithms, including RSA, elliptic curve crypto and
+authenticated encryption. Our cryptographers have systematically surveyed the
+literature and implemented most known attacks. We have over 80 test cases which
+have uncovered more than [40 bugs](doc/bugs.md). For
+example, we found that we could recover the private key of widely-used DSA and
+ECDHC implementations.
+
+While we are committed to develop as many attacks as possible, Project
+Wycheproof is by no means complete. Passing the tests does not imply that the
+library is secure, it just means that it is not vulnerable to the attacks that
+Project Wycheproof tests for. Cryptographers are also constantly discovering
+new attacks. Nevertheless, with Project Wycheproof developers and users now can
+check their libraries against a large number of known attacks, without having
+to spend years reading academic papers or become cryptographers themselves.
+
+For more information on the goals and strategies of Project Wycheproof, please
+check out our [doc](doc/).
+
+### Coverage
+
+Project Wycheproof has tests for the most popular crypto algorithms, including
+
+ - AES-EAX
+ - AES-GCM
+ - [DH](doc/dh.md)
+ - DHIES
+ - [DSA](doc/dsa.md)
+ - [ECDH](doc/ecdh.md)
+ - ECDSA
+ - ECIES
+ - [RSA](doc/rsa.md)
+
+The tests detect whether a library is vulnerable to many attacks, including
+
+ - Invalid curve attacks
+ - Biased nonces in digital signature schemes
+ - Of course, all Bleichenbacher’s attacks
+ - And many more -- we have over 80 test cases
+
+### Usage
+
+Our first set of tests are written in Java, because Java has a common
+cryptographic interface. This allowed us to test multiple providers with a
+single test suite. While this interface is somewhat low level, and should not
+be used directly, we still apply a "defense in depth" argument and expect that
+the implementations are as robust as possible. For example, we consider weak
+default values to be a significant security flaw. We are converting as many
+tests into sets of test vectors to simplify porting the tests to other
+languages. We provide ready-to-use test runners for Java Cryptography
+Architecture providers such as [Bouncy Castle](http://bouncycastle.org),
+[Conscrypt](https://conscrypt.org) and the default providers in
+[OpenJDK](http://openjdk.java.net/).
+
+Project Wycheproof uses the [Bazel](https://bazel.build/) build system, you need
+to [install](https://bazel.build/versions/master/docs/install.html) Bazel to run
+the tests.
+
+Check out the tests
+
+```
+git checkout https://github.com/google/wycheproof.git
+```
+
+To test latest stable version of Bouncy Castle:
+
+```
+bazel test BouncyCastleAllTests
+```
+
+To test other versions, e.g., v1.52:
+
+```
+bazel test BouncyCastleAllTests_1_52
+```
+
+To test all known versions (warning, will take a long time):
+
+```
+bazel test BouncyCastleAllTests_*
+```
+
+ConscryptAllTests and OpenJDKAllTests run the tests against
+[Conscrypt](https://conscrypt.org) and [OpenJDK](http://openjdk.java.net/),
+respectively.
+
+Some of the tests take a very long time to run. If you want to exclude those
+tests, use either BouncyCastleTest, ConscryptTest or OpenJDKTest -- these
+targets exclude all slow tests (i.e., those annotated with @SlowTest).
+
+### Hall of Bugs
+
+Here are some of the notable vulnerabilities that are uncovered by
+Project Wycheproof:
+
+ - OpenJDK's SHA1withDSA leaks private keys > 1024 bits
+ - Test: TODO(thaidn)
+ - This bug is the same as
+[CVE-2003-0971 - GnuPG generated ElGamal signatures that leaked the private key]
+(https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2003-0971)
+
+ - Bouncy Castle's ECDHC leaks private keys
+ - Test: TODO(thaidn)
+
+### Contact and mailing list
+
+If you want to contribute, please read [CONTRIBUTING](CONTRIBUTING) and send us
+pull requests. You can also report bugs or request new tests.
+
+If you'd like to talk to our developers or get notified about major new
+tests, you may want to subscribe to our
+[mailing list](https://groups.google.com/forum/#!forum/wycheproof-users). To
+join, simply send an empty mail to wycheproof-users+subscribe@googlegroups.com.
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..800d7ce
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,99 @@
+maven_jar(
+ name = "bouncycastle_1_46",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.46",
+)
+
+maven_jar(
+ name = "bouncycastle_1_47",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.47",
+)
+
+maven_jar(
+ name = "bouncycastle_1_48",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.48",
+)
+
+maven_jar(
+ name = "bouncycastle_1_49",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.49",
+)
+
+maven_jar(
+ name = "bouncycastle_1_50",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.50",
+)
+
+maven_jar(
+ name = "bouncycastle_1_51",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.51",
+)
+
+maven_jar(
+ name = "bouncycastle_1_52",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.52",
+)
+
+maven_jar(
+ name = "bouncycastle_1_53",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.53",
+)
+
+maven_jar(
+ name = "bouncycastle_1_54",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.54",
+)
+
+maven_jar(
+ name = "bouncycastle_1_55",
+ artifact = "org.bouncycastle:bcprov-jdk15on:1.55",
+)
+
+maven_jar(
+ name = "spongycastle_core_1_50",
+ artifact = "com.madgag.spongycastle:core:1.50.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_prov_1_50",
+ artifact = "com.madgag.spongycastle:prov:1.50.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_core_1_51",
+ artifact = "com.madgag.spongycastle:core:1.51.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_prov_1_51",
+ artifact = "com.madgag.spongycastle:prov:1.51.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_core_1_52",
+ artifact = "com.madgag.spongycastle:core:1.52.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_prov_1_52",
+ artifact = "com.madgag.spongycastle:prov:1.52.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_core_1_53",
+ artifact = "com.madgag.spongycastle:core:1.53.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_prov_1_53",
+ artifact = "com.madgag.spongycastle:prov:1.53.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_core_1_54",
+ artifact = "com.madgag.spongycastle:core:1.54.0.0",
+)
+
+maven_jar(
+ name = "spongycastle_prov_1_54",
+ artifact = "com.madgag.spongycastle:prov:1.54.0.0",
+)
diff --git a/build_defs.bzl b/build_defs.bzl
new file mode 100644
index 0000000..13aa82b
--- /dev/null
+++ b/build_defs.bzl
@@ -0,0 +1,119 @@
+bouncycastle_versions = range(49, 56)
+
+# These targets run all tests.
+def bouncycastle_all_tests(srcs, deps, size, test_class):
+ """BouncyCastle version-specific tests."""
+
+ # Generates BouncyCastleAllTests_1_55, ..., BouncyCastleAllTests_1_49
+ for version in bouncycastle_versions:
+ native.java_test(
+ name = "BouncyCastleAllTests_1_%s" % version,
+ srcs = srcs,
+ deps = deps + [
+ "@bouncycastle_1_%s//jar" % version,
+ ],
+ size = size,
+ test_class = test_class,
+ )
+
+ # Latest stable.
+ # We can't use native.alias, because aliased tests are not run.
+ # So, we simply duplicate the test.
+ native.java_test(
+ name = "BouncyCastleAllTests",
+ srcs = srcs,
+ deps = deps + ["@bouncycastle_1_%s//jar" % max(bouncycastle_versions)],
+ size = size,
+ test_class = test_class,
+ )
+
+# These targets exclude slow tests.
+def bouncycastle_tests(srcs, deps, size, test_class):
+ """BouncyCastle version-specific tests."""
+
+ # Generates BouncyCastleTest_1_55, ..., BouncyCastleTest_1_49
+ for version in bouncycastle_versions:
+ native.java_test(
+ name = "BouncyCastleTest_1_%s" % version,
+ srcs = srcs,
+ deps = deps + [
+ "@bouncycastle_1_%s//jar" % version,
+ ],
+ size = size,
+ test_class = test_class,
+ )
+
+ # Latest stable.
+ # We can't use native.alias, because aliased tests are not run.
+ # So, we simply duplicate the test.
+ native.java_test(
+ name = "BouncyCastleTest",
+ srcs = srcs,
+ deps = deps + ["@bouncycastle_1_%s//jar" % max(bouncycastle_versions)],
+ size = size,
+ test_class = test_class,
+ )
+
+spongycastle_versions = range(50, 55)
+
+# These targets run all tests.
+def spongycastle_all_tests(srcs, deps, size, test_class):
+ """SpongyCastle version-specific tests."""
+
+ # Generates SpongyCastleAllTests_1_54, ..., SpongyCastleAllTests_1_50
+ for version in spongycastle_versions:
+ native.java_test(
+ name = "SpongyCastleAllTests_1_%s" % version,
+ srcs = srcs,
+ deps = deps + [
+ "@spongycastle_core_1_%s//jar" % version,
+ "@spongycastle_prov_1_%s//jar" % version,
+ ],
+ size = size,
+ test_class = test_class,
+ )
+
+ # Latest stable.
+ # We can't use native.alias, because aliased tests are not run.
+ # So, we simply duplicate the test.
+ native.java_test(
+ name = "SpongyCastleAllTests",
+ srcs = srcs,
+ deps = deps + [
+ "@spongycastle_core_1_%s//jar" % max(spongycastle_versions),
+ "@spongycastle_prov_1_%s//jar" % max(spongycastle_versions),
+ ],
+ size = size,
+ test_class = test_class,
+ )
+
+# These targets exclude slow tests.
+def spongycastle_tests(srcs, deps, size, test_class):
+ """SpongyCastle version-specific tests."""
+
+ # Generates SpongyCastleTest_1_54, ..., SpongyCastleTest_1_50
+ for version in spongycastle_versions:
+ native.java_test(
+ name = "SpongyCastleTest_1_%s" % version,
+ srcs = srcs,
+ deps = deps + [
+ "@spongycastle_core_1_%s//jar" % version,
+ "@spongycastle_prov_1_%s//jar" % version,
+ ],
+ size = size,
+ test_class = test_class,
+ )
+
+ # Latest stable.
+ # We can't use native.alias, because aliased tests are not run.
+ # So, we simply duplicate the test.
+ native.java_test(
+ name = "SpongyCastleTest",
+ srcs = srcs,
+ deps = deps + [
+ "@spongycastle_core_1_%s//jar" % max(spongycastle_versions),
+ "@spongycastle_prov_1_%s//jar" % max(spongycastle_versions),
+ ],
+ size = size,
+ test_class = test_class,
+ )
diff --git a/doc/bugs.md b/doc/bugs.md
new file mode 100644
index 0000000..1533e3b
--- /dev/null
+++ b/doc/bugs.md
@@ -0,0 +1,5 @@
+# List of bugs in common algorithms
+* [RSA](rsa.md)
+* [DSA](dsa.md)
+* [ECDH](ecdh.md)
+* [Diffie-Hellman](dh.md)
diff --git a/doc/dh.md b/doc/dh.md
new file mode 100644
index 0000000..ca8c410
--- /dev/null
+++ b/doc/dh.md
@@ -0,0 +1,141 @@
+# Diffie-Hellman
+
+## Subgroup confinement attacks
+
+The papers by van Oorshot and Wiener [OW96] rsp. Lim and Lee [LL98] show that
+Diffie-Hellman keys can be found much faster if the short exponents are used and
+if the multiplicative group modulo p contains small subgroups. In particular an
+attacker can try to send a public key that is an element of a small subgroup. If
+the receiver does not check for such elements then may be possible to find the
+private key modulo the order of the small subgroup. Several countermeasures
+against such attacks have been proposed: For example IKE uses fields of order p
+where p is a safe prime (i.e. $$q=(p-1)/2),$$ hence the only elements of small
+order are 1 and p-1.
+
+[NIST SP 800-56A] rev. 2, Section 5.5.1.1 only requires that the size of the
+subgroup generated by the generator g is big enough to prevent the baby-step
+giant-step algorithm. I.e. for 80-bit security p must be at least 1024 bits long
+and the prime q must be at least 160 bits long. A 2048 bit prime p and a 224 bit
+prime q are sufficient for 112 bit security. To avoid subgroup confinment
+attacks NIST requires that public keys are validated, i.e. by checking that a
+public key y satisfies the conditions $$2 \leq y \leq p-2$$ and $$y^q \mod p =
+1$$ (Section 5.6.2.3.1). Further, after generating the shared secret $$z =
+y_a^{x_b} \mod p$$ each party should check that $$z \neq 1.$$ RFC 2785 contains
+similar recommendations. The public key validation described by NIST requires
+that the order q of the generator g is known to the verifier. Unfortunately, the
+order q is missing in [PKCS #3]. [PKCS #3] describes the Diffie-Hellman
+parameters only by the values p, g and optionally the key size in bits.
+
+The class DHParameterSpec that defines the Diffie-Hellman parameters in JCE
+contains the same values as [PKCS #3]. In particular, it does not contain the
+order of the subgroup q. Moreover, the SUN provider uses the minimal sizes
+specified by NIST for q. Essentially the provider reuses the parameters for DSA.
+
+Therefore, there is no guarantee that an implementation of Diffie-Hellman is secure against
+subgroup confinement attacks. Without a key validation it is insecure to use the key-pair
+generation from [NIST SP 800-56A] Section 5.6.1.1 (The key-pair generation there only requires that
+static and ephemeral private keys are randomly chosen in the range \\(1..q-1)\\).
+
+To avoid big disasters the tests below require that key sizes are not minimal. I.e., currently
+the tests require at least 512 bit keys for 1024 bit fields. We use this lower limit because that
+is what the SUN provider is currently doing.
+
+TODO(bleichen): Find a reference supporting or disproving that decision.
+
+## Weak parameters
+
+The DH parameters must be carefully chosen to avoid security issues. A panel at
+Eurocrypt'92 discussed the possiblity of trapdoors in DL based primitives
+[Eurocrypt92 panel]. A. Lenstra pointed out that the primes chould be chosen
+such that the special number field sieve can be used to compute discrete
+logarithms. Gordon has analyzed methods to generate and detect weak parameters
+[G92]. Section 4 of Gordons paper describes a method that can detect some
+special cases, but no general method was given. Recently Fried et al. showed
+that 1024 bit discrete logarithms with the special number field sieve are
+feasible [FGHT16]. Moreover some libraries use primes that are susceptible to
+this attack [FGHT16].
+
+TODO(bleichen): So far not test for weak DH parameters has been implemented.
+Possibly we should at least implement a test that detects special cases, so
+that weak primes (such as the one used in libtomcrypt) are detected.
+
+DH implementations are sometimes misconfigured. Adrian et al. [WeakDh] analyzed
+various implementations and found for example the following problems in the
+parameters: p is sometimes composite, p-1 contains no large prime factor, q is
+used instead of the generator g.
+
+## References
+[Eurocrypt92 panel]: "The Eurocrypt'92 Controversial Issue Trapdoor Primes and Moduli",
+EUROCRYPT '92, LNCS 658, pp. 194-199.
+
+[G92]: D. M. Gordon. "Designing and detecting trapdoors for discrete log
+cryptosystems." CRYPTO’92, pp. 66–75.
+
+\[FGHT16]: J. Fried, P. Gaudry, N. Heininger, E. Thome. "A kilobit hidden SNFS
+discrete logarithm computation". http://eprint.iacr.org/2016/961.pdf
+
+[OW96]: P. C. van Oorschot, M. J. Wiener, "On Diffie-Hellman key agreement with short exponents",
+Eurocrypt 96, pp 332–343.
+
+[LL98]: C.H. Lim and P.J. Lee,
+"A key recovery attack on discrete log-based schemes using a prime order subgroup",
+CRYPTO' 98, pp 249–263.
+
+[WeakDh]: D. Adrian, K. Bhargavan, Z. Durumeric, P. Gaudry, M. Green,
+J. A. Halderman, N. Heninger, D. Springall, E. Thomé, Luke Valenta,
+B. VanderSloot, E. Wustrow, S. Zanella-Béguelink, P. Zimmermann,
+"Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice"
+https://weakdh.org/imperfect-forward-secrecy-ccs15.pdf
+
+[NIST SP 800-56A], revision 2, May 2013
+http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
+
+[PKCS #3]: "Diffie–Hellman Key Agreement",
+http://uk.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm
+
+[RFC 2785]: R. Zuccherato,
+"Methods for Avoiding 'Small-Subgroup' Attacks on the Diffie-Hellman Key Agreement Method for S/MIME",
+March 2000
+https://www.ietf.org/rfc/rfc2785.txt
+
+<!--
+## Sources that might be used for additional tests:
+
+CVE-2015-3193: The Montgomery squaring implementation in crypto/bn/asm/x86_64-mont5.pl
+in OpenSSL 1.0.2 before 1.0.2e on the x86_64 platform, as used by the BN_mod_exp function,
+mishandles carry propagation
+https://blog.fuzzing-project.org/31-Fuzzing-Math-miscalculations-in-OpenSSLs-BN_mod_exp-CVE-2015-3193.html
+
+CVE-2016-0739: libssh before 0.7.3 improperly truncates ephemeral secrets generated for the
+(1) diffie-hellman-group1 and (2) diffie-hellman-group14 key exchange methods to 128 bits ...
+
+CVE-2015-1787 The ssl3_get_client_key_exchange function in s3_srvr.c in OpenSSL 1.0.2 before
+1.0.2a, when client authentication and an ephemeral Diffie-Hellman ciphersuite are enabled,
+allows remote attackers to cause a denial of service (daemon crash) via a ClientKeyExchange
+message with a length of zero.
+
+CVE-2015-0205 The ssl3_get_cert_verify function in s3_srvr.c in OpenSSL 1.0.0 before 1.0.0p
+and 1.0.1 before 1.0.1k accepts client authentication with a Diffie-Hellman (DH) certificate
+without requiring a CertificateVerify message, which allows remote attackers to obtain access
+without knowledge of a private key via crafted TLS Handshake Protocol traffic to a server that
+recognizes a Certification Authority with DH support.
+
+CVE-2016-0701 The DH_check_pub_key function in crypto/dh/dh_check.c in OpenSSL 1.0.2 before
+1.0.2f does not ensure that prime numbers are appropriate for Diffie-Hellman (DH) key exchange,
+which makes it easier for remote attackers to discover a private DH exponent by making multiple
+handshakes with a peer that chose an inappropriate number, as demonstrated by a number in an
+X9.42 file.
+
+CVE-2006-1115 nCipher HSM before 2.22.6, when generating a Diffie-Hellman public/private key
+pair without any specified DiscreteLogGroup parameters, chooses random parameters that could
+allow an attacker to crack the private key in significantly less time than a brute force attack.
+
+CVE-2015-1716 Schannel in Microsoft Windows Server 2003 SP2, Windows Vista SP2, Windows Server
+2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and
+Windows RT Gold and 8.1 does not properly restrict Diffie-Hellman Ephemeral (DHE) key lengths,
+which makes it easier for remote attackers to defeat cryptographic protection mechanisms via
+unspecified vectors, aka "Schannel Information Disclosure Vulnerability.
+
+CVE-2015-2419: Random generation of the prime p allows Pohlig-Hellman and probably other
+stuff.
+-->
diff --git a/doc/dsa.md b/doc/dsa.md
new file mode 100644
index 0000000..0c2f631
--- /dev/null
+++ b/doc/dsa.md
@@ -0,0 +1,192 @@
+# DSA
+
+[TOC]
+
+The digital signature algorithm (DSA) is one of three signature schemes
+descripted in the digital signature standard [DSS].
+
+## Key generation
+
+4.2 Selection of Parameter Sizes and Hash Functions for DSA
+The DSS specifies the following choices for the pair (L,N),
+where L is the size of p in bits and N is the size of q in bits:
+
+L | N
+---:|----:
+1024| 160
+2048| 224
+2048| 256
+3072| 256
+
+The tests expect the following properties of the parameters used during
+key generation:
+
+* If only the parameter L is specified by the caller then N should be one
+ of the options proposed in [DSS].
+* If no size is specified then L should be at least 2048. This is the minimal
+ key size recommended by NIST for the period up to the year 2030.
+
+## Signature generation
+
+The DSA signature algorithm requires that each signature is computed with a new
+one-time secret k. This secret value should be close to uniformly distributed.
+If that is not the case then DSA signatures can leak the private key that was
+used to generate the signature. Two methods for generating the one-time secrets
+are described in FIPS PUB 186-4, Section B.5.1 or B.5.2 [DSS]. There is also the
+possibility that the use of mismatched implementations for key generation and
+signature generation are leaking the private keys.
+
+## Signature verification
+
+A DSA signature is a DER encoded tuple of two integers (r,s). To verify a
+signature the verifier first checks $$0 < r < q$$ and $$0 < s < q$$. The
+verifier then computes:
+
+$$
+\begin{array}{l}
+w=s^{-1} \bmod q\\
+u1 = w \cdot H(m) \bmod q\\
+u2 = w \cdot r \bmod q\\
+\end{array}
+$$
+
+and then verifies that \\(r = (g^{u1}y^{u2} \bmod p) \bmod q\\)
+
+## Incorrect computations and range checks.
+
+Some libraries return 0 as the modular inverse of 0 or q.
+This can happen if the library computes the modular
+inverse of s as \\(w=s^{q-2} \mod q\\) (gpg4browsers) of simply
+if the implementations is buggy (pycrypto). if additionally to such
+a bug the range of r,s is not or incorrectly tested then it might
+be feasible to forge signatures with the values (r=1, s=0) or (r=1, s=q).
+In particular, if a library can be forced to compute \\(s^{-1} \mod q = 0\\)
+then the verification would compute \\( w = u1 = u2 = 0 \\) and hence
+\\( (g^{u1}y^{u2} \mod p) \mod q = 1 .\\)
+
+## Timing attacks
+
+TBD
+
+# Some notable failures of crypto libraries.
+
+## JDK
+
+The jdk8 implementation of SHA1withDSA previously checked the key size as follows:
+
+```java
+@Override
+ protected void checkKey(DSAParams params)
+ throws InvalidKeyException {
+ int valueL = params.getP().bitLength();
+ if (valueL > 1024) {
+ throw new InvalidKeyException("Key is too long for this algorithm");
+ }
+ }
+```
+
+This check was reasonable, it partially ensures conformance with the NIST
+standard. In most cases would prevent the attack described above.
+
+However, Oracle released a patch that removed the length verification in DSA in
+jdk9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/edd7a67585a5
+https://bugs.openjdk.java.net/browse/JDK-8039921
+
+The new code is here:
+http://hg.openjdk.java.net/jdk9/dev/jdk/file/edd7a67585a5/src/java.base/share/classes/sun/security/provider/DSA.java
+
+The change was further backported to jdk8:
+http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/3212f1631643
+
+Doing this was a serious mistake. It easily allowed incorrect implementations.
+While generating 2048 bit DSA keys in jdk7 was not yet supported, doing so in
+jdk8 is. To trigger this bug in jdk7 an application had to use a key generated
+by a third party library (e.g. OpenSSL). Now, it is possible to trigger the bug
+just using JCE. Moreover, the excessive use of default values in JCE makes it
+easy to go wrong and rather difficult to spot the errors.
+
+The bug was for example triggered by the following code snippet:
+
+```java
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");
+ Keygen.initialize(2048);
+ KeyPair keypair = keygen.genKeyPair();
+ Signature s = Signature.getInstance("DSA");
+ s.initSign(keypair.getPrivate());
+```
+
+The first three lines generate a 2048 bit DSA key. 2048 bits is currently the
+smallest key size recommended by NIST.
+
+```java
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");
+ Keygen.initialize(2048);
+ KeyPair keypair = keygen.genKeyPair();
+```
+
+The key size specifies the size of p but not the size of q. The NIST standard
+allows either 224 or 256 bits for the size of q. The selection typically depends
+on the library. The Sun provider uses 224. Other libraries e.g. OpenSSL
+generates by default a 256 bit q for 2048 bit DSA keys.
+
+The next line contains a default in the initialization
+
+```java
+    Signature s = Signature.getInstance("DSA");
+```
+This line is equivalent to
+
+```java
+    Signature s = Signature.getInstance("SHA1withDSA");
+```
+Hence the code above uses SHA1 but with DSA parameters generated for SHA-224
+or SHA-256 hashes. Allowing this combination by itself is already a mistake,
+but a flawed implementaion made the situation even worse.
+
+The implementation of SHA1withDSA assumeed that the parameter q is 160 bits
+long and used this assumption to generate a random 160-bit k when generating a
+signature instead of choosing it uniformly in the range (1,q-1).
+Hence, k severely biased. Attacks against DSA with biased k are well known.
+Howgrave-Graham and Smart analyzed such a situation [HS99]. Their results
+show that about 4 signatrues leak enough information to determine
+the private key in a few milliseconds.
+Nguyen analyzed a similar flaw in GPG [N04].
+I.e., Section 3.2 of Nguyens paper describes essentially the same attack as
+used here. More generally, attacks based on lattice reduction were developed
+to break a variety of cryptosystems such as the knapsack cryptosystem [O90].
+
+## Further notes
+
+The short algorithm name “DSA” is misleading, since it hides the fact that
+`Signature.getInstance(“DSA”)` is equivalent to
+`Signature.getInstance(“SHA1withDSA”)`. To reduce the chance of a
+misunderstanding short algorithm names should be deprecated. In JCE the hash
+algorithm is defined by the algorithm. I.e. depending on the hash algorithm to
+use one would call one of:
+
+```java
+ Signature.getInstance(“SHA1withDSA”);
+ Signature.getInstance(“SHA224withDSA”);
+ Signature.getInstance(“SHA256withDSA”);
+```
+
+A possible way to push such a change are code analysis tools. "DSA" is in good
+company with other algorithm names “RSA”, “AES”, “DES”, all of which default to
+weak algorithms.
+
+## References
+
+[HS99]: N.A. Howgrave-Graham, N.P. Smart,
+ “Lattice Attacks on Digital Signature Schemes”
+ http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf
+
+[N04]: Phong Nguyen, “Can we trust cryptographic software? Cryptographic flaws
+ in Gnu privacy guard 1.2.3”, Eurocrypt 2004,
+ https://www.iacr.org/archive/eurocrypt2004/30270550/ProcEC04.pdf
+
+[O90]: A. M. Odlyzko, "The rise and fall of knapsack cryptosystems", Cryptology
+ and Computational Number Theory, pp.75-88, 1990
+
+[DSS]: FIPS PUB 186-4, "Digital Signature Standard (DSS)", National Institute
+ of Standards and Technology, July 2013
+ http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
diff --git a/doc/ecdh.md b/doc/ecdh.md
new file mode 100644
index 0000000..c86b140
--- /dev/null
+++ b/doc/ecdh.md
@@ -0,0 +1,58 @@
+
+# ECDH
+
+[TOC]
+
+##ECDH description:
+See https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman
+
+##Bugs
+Some libraries do not check if the elliptic curve points received from another
+party are points on the curve. Encodings of public keys typically contain the
+curve for the public key point. If such an encoding is used in the key exchange
+then it is important to check that the public and secret key used to compute
+the shared ECDH secret are using the same curve.
+Some libraries fail to do this check.
+
+**Potential exploits:**
+The damage done depends on the protocol that uses ECDH. E.g. if ECDH is used
+with ephemeral keys then the damage is typically limited. If the EC keys are
+static, i.e. used for multiple key exchanges then a failure to verify a public
+point can disclose the private key used in the same protocol.
+(To do: add papers describing the attack).
+
+##Libraries
+**Sun JCE provider:**
+ECDH does not check if the points are on the curve.
+The implementer must do this.
+
+**Bouncycastle:**
+The ECDH implementation does not check if the point is on the curve.
+Furthermore, Bouncycastle does not even check if the public and private key are
+on the same curve. It performs a point multiplication \\(x \cdot Y\\) over the
+curve specified by the public key.
+
+**OpenSSL:**
+Point verification is done in OpenSSL if the right functions are used.
+Since OpenSSL is not well documented it is a bit tricky to find the right
+functions.
+(To do: maybe add an example).
+
+##Countermeasures
+TODO:
+* use point compression. Formats such as X509EncodedKeySpec
+in Java include bits that indicate whether the point is compressed or not.
+Hence an attacker can always choose to use uncompressed points as long as this
+option is incorrectly implemented.
+* check that public and private key use the same curve
+* restrict the protocol to named curves
+* reconstruct the public key explicitly using the parameters of the private
+ key.
+
+**Further recommendations:**
+If possible I also check if the points are on the curve after point
+multiplications on an elliptic curve in the hope to catch implementation
+and hardware faults.
+
+## Some notable bugs:
+* ECDHC in bouncy castle could be broken by modifying the order of the public key.
diff --git a/doc/index.md b/doc/index.md
new file mode 100644
index 0000000..c664ba1
--- /dev/null
+++ b/doc/index.md
@@ -0,0 +1,80 @@
+# Project Wycheproof
+
+This page describes the goals and strategies of project Wycheproof. See
+[README](../README.md) for introduction to the project.
+
+## Defense in depth
+
+There are a number of tests where we check for expected behaviour
+rather than exploitability. Examples:
+
+* default values: we expect that default values are reasonable and correspond
+ to recommendations by current standards. Concretely, in 2016 it is not OK
+ if an RSA key generation uses 1024 bits as default or digital signatures
+ use SHA-1 as default.
+* timing attacks: any timing that relation between keys (or other sensitive)
+ data and the measured time fails the test. However tests are set up
+ such that too much noise during the test can prevent that a relation
+ is detected.
+* wrong exceptions: The JCE interface often specifies the exceptions that
+ should be thrown when the input is invalid. We expect the specified
+ exceptions in the tests.
+* leaking information through exceptions: While it is a good practice to not
+ return detailed logs to a sender, we consider text in exceptions as
+ information that a potential attacker can learn. For example padding
+ failures during decryption should not contain information about the
+ reason why a decryption failed.
+* RSA PKCS #1 signatures: If a signature verification allows signatures
+ with lots of modifications, then RSA signatures can be forged for small
+ public exponents. Tests do not measure how many bytes can be modified.
+ Any accepted modification of the PKCS #1 padding fails the test.
+
+## Compatibility between providers
+
+One of the goals of Wycheproof is to test for compatibility issues.
+Switching JCE providers should not introduce vulnerabilities simply because
+the solution was developed with another provider.
+
+An example for this was the following observation: When using AES-GCM then
+javax.crypto.CipherInputStream worked sort of with JCE and
+org.bouncycastle.jcajce.io.CipherInputStream.java worked with BouncyCastle.
+However, authentication was skipped in some cases when
+javax.crypto.CipherInputStream was used with BouncyCastle.
+
+## Comparing cryptographic libraries is not a primary goal
+
+Because of the strategies mentioned above we expect that a comparison of
+cryptographic libraries based on the bugs found would be biased:
+
+* Libraries used internally in Google get more attention.
+ Serious vulnerabilities in these libraries should be fixed at the time the
+ tests are added to Wycheproof. On the other hand it is also likely that
+ tests find a larger number of bugs in thsese libraries when old versions are
+ tested.
+* Tests often check for expected behaviour and compatibility.
+ Excpected behaviour is often defined by a prominent library.
+ Pointing out such problems can therefore penalize smaller third party
+ libraries.
+* We are working toward covering as many potential vulnerabilities as possible
+ with test vectors, because this simplifies porting the tests to other
+ languages or interfaces. Thus a single test case can cover multiple
+ vulnerabilities.
+
+We are not trying to remove this bias when this interferes with more important
+goals such as early reporting.
+Hence we are reluctant to publish comparisons.
+
+
+## Thoughts on the design of cryptographic libraries
+
+We should promote robust interfaces with the goal to simplify
+the use of the library, codereviews of applications using the
+library and testing the library.
+
+* When cryptrographic primitives require randomness then the random
+ numbers should be chosen by the library. It shouldn't be possible
+ for a user to provide randomness. If the library itself chooses the
+ randomness then it is possible (at least to some degree) to check
+ that the random number generation is appropriate for the primitive.
+ If the user can provide the randomness then it is not possible to
+ catch this in our tests.
diff --git a/doc/rsa.md b/doc/rsa.md
new file mode 100644
index 0000000..09ee6d0
--- /dev/null
+++ b/doc/rsa.md
@@ -0,0 +1,130 @@
+# RSA
+
+[TOC]
+
+## RSA key generation
+
+**Default size:** If a library supports a key default size for RSA keys then
+this key size should be at least 2048 bits. This limit is based on the minimum
+recommendation of [NIST SP 800-57] part1 revision 4, Table 2, page 53. NIST
+recommends a minimal security strength of 112 bits for keys used until 2030. 112
+bit security strength translates to a minimal key size of 2048 bits. Other
+organizations recommend somewhat different sizes: [Enisa], Section 3.6 also
+suggests that 2048-bit RSA keys provide a security strength of about 112 bits,
+but recommends a security strength of 128 bits for near term systems, hence 3072
+bit RSA keys. [ECRYPT II], Section 13.3 suggests at least 2432 bits for new
+keys.
+
+All the references above clearly state that keys smaller than 2048 bits should
+only be used in legacy cases. Therefore, it seems wrong to use a default key
+size smaller than 2048 bits. If a user really wants a small RSA key then such a
+choice should be made by explicitly providing the desired key length during the
+initalization of a key pair generator.
+
+According to https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
+every implementation of the Java platform is required to implement RSA with both 1024 and
+2048 bit key sizes. Hence a 2048 bit default should not lead to compatibility problems.
+
+**Cryptographically strong random numbers:**
+So far the tests check that java.util.Random is not used. This needs to be
+extended.
+
+**Other bugs:**
+The public exponent e should be larger than 1 [CVE-1999-1444]
+
+## RSA PKCS #1 v1.5 encryption
+
+PKCS #1 v1.5 padding is susceptible to adaptive chosen ciphertext attacks and
+hence should be avoided [B98]. The difficulty of exploiting protocols using
+PKCS #1 v1.5 encryption often depends on the amount of information leaked after
+decrypting corrupt ciphertexts. Implementations frequently leak information
+about the decrypted plaintext in form of error messages. The content of the
+error messages are extremely helpful to potential attackers. Bardou et al.
+[BFKLSST12] analyze the difficult of attacks based on different types of
+information leakage. Smart even describes an attack that only needs about 40
+chosen ciphertexts [S10], though in this case the encryption did not use PKCS #1
+padding.
+
+**Bugs**
+
+* Bouncycastle throws detailed exceptions:
+ InvalidCipherTextException("unknown block type") or
+ InvalidCipherTextException("block padding incorrect").
+
+<!-- the SUN provider used to include that block type -->
+
+**Tests**
+To test whether an implementation leaks more information than necessary a test decrypts
+some random ciphertexts and catches the exceptions. If the exceptions are distinguishable
+then the test assumes that unnecessary information about the padding is leaked.
+
+Due to the nature of unit tests not every attack can be detected this way.
+Some attacks require a large number of ciphertexts to be detected if random ciphertexts
+are used. For example Klima et al. [KPR03] describe an implementation flaw that could not
+be detected with our test.
+
+Timing leakages because of differences in parsing the padding can leak information
+(e.g. CVE-2015-7827). Such differences are too small to be reliably detectable in
+unit tests.
+
+## RSA OAEP
+Manger describes an chosen ciphertext attack against RSA in [M01].
+There are implementations that were subseptible to Mangers attack,
+e.g. [CVE-2012-5081].
+
+## RSA PKCS1 signatures
+**Potential problems:**
+
+ * Some libraries parse PKCS#1 padding during signature verification incorrectly.
+ * Some libraries determine the hash function from the signature
+ (rather than encoding this in the key)
+ Effect:
+ * If the verification is buggy then an attacker might be able to generate
+ signatures for keys with a small (i.e. e=3) public exponent.
+ * If the hash algorithm is not determined by in an authentic manner then preimage
+ attacks against weak hashes are possible, even if the hashes are not used
+ by the signer.
+
+**Countermeasures:**
+A good way to implement RSA signature verification is described in the standard PKCS#1
+v.2.2 Section 8.2.2.
+This standard proposes to reconstruct the padding during verification and
+compare the padded hash to the value \\(s^e \bmod n\\) obtained from applying a public
+key exponentiation to the signature s.
+Since this is a recurring bug it makes also a lot of sense to avoid small
+public exponents and prefer for example e=65537 .
+
+**List of broken implementations**
+This is a large list.
+
+## References
+[B98]: D. Bleichenbacher, "Chosen ciphertext attacks against protocols based on the RSA encryption
+ standard PKCS# 1" Crypto 98
+
+[M01]: J. Manger, "A chosen ciphertext attack on RSA optimal asymmetric encryption padding (OAEP)
+ as standardized in PKCS# 1 v2.0", Crypto 2001 This paper shows that OAEP is susceptible
+ to a chosen ciphertext attack if error messages distinguish between different failure
+ condidtions.
+[S10]: N. Smart, "Errors matter: Breaking RSA-based PIN encryption with thirty ciphertext validity
+ queries" RSA conference, 2010 This paper shows that padding oracle attacks can be
+ successful with even a small number of queries.
+
+[KPR03]: V. Klima, O. Pokorny, and T. Rosa, "Attacking RSA-based Sessions in SSL/TLS"
+ https://eprint.iacr.org/2003/052/
+
+[BFKLSST12]: "Efficient padding oracle attacks on cryptographic hardware"
+R. Bardou, R. Focardi, Y. Kawamoto, L. Simionato, G. Steel, J.K. Tsay, Crypto 2012
+
+[NIST SP 800-57]: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf
+
+[Enisa]: "Algorithms, key size and parameters report – 2014"
+https://www.enisa.europa.eu/publications/algorithms-key-size-and-parameters-report-2014
+
+\[ECRYPT II]: Yearly Report on Algorithms and Keysizes (2011-2012),
+http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf
+
+[CVE-1999-1444]: Alibaba 2.0 generated RSA key pairs with an exponent 1
+
+[CVE-2012-5081]: Java JSSE provider leaked information through
+ exceptions and timing. Both the PKCS #1 padding and the OAEP padding were broken:
+ http://www-brs.ub.ruhr-uni-bochum.de/netahtml/HSS/Diss/MeyerChristopher/diss.pdf
diff --git a/java/com/google/security/wycheproof/BouncyCastleAllTests.java b/java/com/google/security/wycheproof/BouncyCastleAllTests.java
new file mode 100644
index 0000000..47a4dcf
--- /dev/null
+++ b/java/com/google/security/wycheproof/BouncyCastleAllTests.java
@@ -0,0 +1,53 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * BouncyCastleAllTests runs all tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesEaxTest.class,
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DhiesTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ EciesTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class,
+})
+@Provider(ProviderType.BOUNCY_CASTLE)
+public final class BouncyCastleAllTests {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyThisProvider(new BouncyCastleProvider());
+ }
+}
diff --git a/java/com/google/security/wycheproof/BouncyCastleTest.java b/java/com/google/security/wycheproof/BouncyCastleTest.java
new file mode 100644
index 0000000..941b94f
--- /dev/null
+++ b/java/com/google/security/wycheproof/BouncyCastleTest.java
@@ -0,0 +1,55 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * BouncyCastleTest excludes {@code @SlowTest} tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesEaxTest.class,
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DhiesTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ EciesTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class,
+})
+@Provider(ProviderType.BOUNCY_CASTLE)
+@Fast
+public final class BouncyCastleTest {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyThisProvider(new BouncyCastleProvider());
+ }
+}
diff --git a/java/com/google/security/wycheproof/ConscryptTest.java b/java/com/google/security/wycheproof/ConscryptTest.java
new file mode 100644
index 0000000..c4f58d5
--- /dev/null
+++ b/java/com/google/security/wycheproof/ConscryptTest.java
@@ -0,0 +1,51 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.conscrypt.OpenSSLProvider;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Conscrypt is a Java security provider that uses OpenSSL. See {@link https://conscrypt.org/}.
+ * ConscryptTest excludes {@code @SlowTest} tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class
+})
+@Provider(ProviderType.CONSCRYPT)
+@Fast
+public final class ConscryptTest {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyThisProvider(new OpenSSLProvider());
+ }
+}
diff --git a/java/com/google/security/wycheproof/EcUtil.java b/java/com/google/security/wycheproof/EcUtil.java
new file mode 100644
index 0000000..f464cba
--- /dev/null
+++ b/java/com/google/security/wycheproof/EcUtil.java
@@ -0,0 +1,454 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+
+/**
+ * Some utilities for testing Elliptic curve crypto. This code is for testing only and hasn't been
+ * reviewed for production.
+ */
+public class EcUtil {
+ /**
+ * Returns the ECParameterSpec for a named curve. Not every provider implements the
+ * AlgorithmParameters. Therefore, most test use alternative functions.
+ */
+ public static ECParameterSpec getCurveSpec(String name)
+ throws NoSuchAlgorithmException, InvalidParameterSpecException {
+ AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
+ parameters.init(new ECGenParameterSpec(name));
+ return parameters.getParameterSpec(ECParameterSpec.class);
+ }
+
+ /**
+ * Returns the ECParameterSpec for a named curve. Only a handful curves that are used in the tests
+ * are implemented.
+ */
+ public static ECParameterSpec getCurveSpecRef(String name) throws NoSuchAlgorithmException {
+ if (name.equals("secp224r1")) {
+ return getNistP224Params();
+ } else if (name.equals("secp256r1")) {
+ return getNistP256Params();
+ } else if (name.equals("secp384r1")) {
+ return getNistP384Params();
+ } else if (name.equals("secp521r1")) {
+ return getNistP521Params();
+ } else if (name.equals("brainpoolp256r1")) {
+ return getBrainpoolP256r1Params();
+ } else {
+ throw new NoSuchAlgorithmException("Curve not implemented:" + name);
+ }
+ }
+
+ public static ECParameterSpec getNistCurveSpec(
+ String decimalP, String decimalN, String hexB, String hexGX, String hexGY) {
+ final BigInteger p = new BigInteger(decimalP);
+ final BigInteger n = new BigInteger(decimalN);
+ final BigInteger three = new BigInteger("3");
+ final BigInteger a = p.subtract(three);
+ final BigInteger b = new BigInteger(hexB, 16);
+ final BigInteger gx = new BigInteger(hexGX, 16);
+ final BigInteger gy = new BigInteger(hexGY, 16);
+ final int h = 1;
+ ECFieldFp fp = new ECFieldFp(p);
+ java.security.spec.EllipticCurve curveSpec = new java.security.spec.EllipticCurve(fp, a, b);
+ ECPoint g = new ECPoint(gx, gy);
+ ECParameterSpec ecSpec = new ECParameterSpec(curveSpec, g, n, h);
+ return ecSpec;
+ }
+
+ public static ECParameterSpec getNistP224Params() {
+ return getNistCurveSpec(
+ "26959946667150639794667015087019630673557916260026308143510066298881",
+ "26959946667150639794667015087019625940457807714424391721682722368061",
+ "b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34");
+ }
+
+ public static ECParameterSpec getNistP256Params() {
+ return getNistCurveSpec(
+ "115792089210356248762697446949407573530086143415290314195533631308867097853951",
+ "115792089210356248762697446949407573529996955224135760342422259061068512044369",
+ "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+ "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+ "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5");
+ }
+
+ public static ECParameterSpec getNistP384Params() {
+ return getNistCurveSpec(
+ "3940200619639447921227904010014361380507973927046544666794829340"
+ + "4245721771496870329047266088258938001861606973112319",
+ "3940200619639447921227904010014361380507973927046544666794690527"
+ + "9627659399113263569398956308152294913554433653942643",
+ "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
+ + "c656398d8a2ed19d2a85c8edd3ec2aef",
+ "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
+ + "5502f25dbf55296c3a545e3872760ab7",
+ "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
+ + "0a60b1ce1d7e819d7a431d7c90ea0e5f");
+ }
+
+ public static ECParameterSpec getNistP521Params() {
+ return getNistCurveSpec(
+ "6864797660130609714981900799081393217269435300143305409394463459"
+ + "18554318339765605212255964066145455497729631139148085803712198"
+ + "7999716643812574028291115057151",
+ "6864797660130609714981900799081393217269435300143305409394463459"
+ + "18554318339765539424505774633321719753296399637136332111386476"
+ + "8612440380340372808892707005449",
+ "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
+ + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+ "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
+ + "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+ "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
+ + "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650");
+ }
+
+ public static ECParameterSpec getBrainpoolP256r1Params() {
+ BigInteger p =
+ new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16);
+ BigInteger a =
+ new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16);
+ BigInteger b =
+ new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16);
+ BigInteger x =
+ new BigInteger("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16);
+ BigInteger y =
+ new BigInteger("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16);
+ BigInteger n =
+ new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16);
+ final int h = 1;
+ ECFieldFp fp = new ECFieldFp(p);
+ EllipticCurve curve = new EllipticCurve(fp, a, b);
+ ECPoint g = new ECPoint(x, y);
+ return new ECParameterSpec(curve, g, n, h);
+ }
+
+ /**
+ * Compute the Legendre symbol of x mod p. This implementation is slow. Faster would be the
+ * computation for the Jacobi symbol.
+ *
+ * @param x an integer
+ * @param p a prime modulus
+ * @returns 1 if x is a quadratic residue, -1 if x is a non-quadratic residue and 0 if x and p are
+ * not coprime.
+ * @throws GeneralSecurityException when the computation shows that p is not prime.
+ */
+ public static int legendre(BigInteger x, BigInteger p) throws GeneralSecurityException {
+ BigInteger q = p.subtract(BigInteger.ONE).shiftRight(1);
+ BigInteger t = x.modPow(q, p);
+ if (t.equals(BigInteger.ONE)) {
+ return 1;
+ } else if (t.equals(BigInteger.ZERO)) {
+ return 0;
+ } else if (t.add(BigInteger.ONE).equals(p)) {
+ return -1;
+ } else {
+ throw new GeneralSecurityException("p is not prime");
+ }
+ }
+
+ /**
+ * Computes a modular square root. Timing and exceptions can leak information about the inputs.
+ * Therefore this method must only be used in tests.
+ *
+ * @param x the square
+ * @param p the prime modulus
+ * @returns a value s such that s^2 mod p == x mod p
+ * @throws GeneralSecurityException if the square root could not be found.
+ */
+ public static BigInteger modSqrt(BigInteger x, BigInteger p) throws GeneralSecurityException {
+ if (p.signum() != 1) {
+ throw new GeneralSecurityException("p must be positive");
+ }
+ x = x.mod(p);
+ BigInteger squareRoot = null;
+ // Special case for x == 0.
+ // This check is necessary for Cipolla's algorithm.
+ if (x.equals(BigInteger.ZERO)) {
+ return x;
+ }
+ if (p.testBit(0) && p.testBit(1)) {
+ // Case p % 4 == 3
+ // q = (p + 1) / 4
+ BigInteger q = p.add(BigInteger.ONE).shiftRight(2);
+ squareRoot = x.modPow(q, p);
+ } else if (p.testBit(0) && !p.testBit(1)) {
+ // Case p % 4 == 1
+ // For this case we use Cipolla's algorithm.
+ // This alogorithm is preferrable to Tonelli-Shanks for primes p where p-1 is divisible by
+ // a large power of 2, which is a frequent choice since it simplifies modular reduction.
+ BigInteger a = BigInteger.ONE;
+ BigInteger d = null;
+ while (true) {
+ d = a.multiply(a).subtract(x).mod(p);
+ // Computes the Legendre symbol. Using the Jacobi symbol would be a faster. Using Legendre
+ // has the advantage, that it detects a non prime p with high probability.
+ // On the other hand if p = q^2 then the Jacobi (d/p)==1 for almost all d's and thus
+ // using the Jacobi symbol here can result in an endless loop with invalid inputs.
+ int t = legendre(d, p);
+ if (t == -1) {
+ break;
+ } else {
+ a = a.add(BigInteger.ONE);
+ }
+ }
+ // Since d = a^2 - n is a non-residue modulo p, we have
+ // a - sqrt(d) == (a+sqrt(d))^p (mod p),
+ // and hence
+ // n == (a + sqrt(d))(a - sqrt(d) == (a+sqrt(d))^(p+1) (mod p).
+ // Thus if n is square then (a+sqrt(d))^((p+1)/2) (mod p) is a square root of n.
+ BigInteger q = p.add(BigInteger.ONE).shiftRight(1);
+ BigInteger u = a;
+ BigInteger v = BigInteger.ONE;
+ for (int bit = q.bitLength() - 2; bit >= 0; bit--) {
+ // Compute (u + v sqrt(d))^2
+ BigInteger tmp = u.multiply(v);
+ u = u.multiply(u).add(v.multiply(v).mod(p).multiply(d)).mod(p);
+ v = tmp.add(tmp).mod(p);
+ if (q.testBit(bit)) {
+ tmp = u.multiply(a).add(v.multiply(d)).mod(p);
+ v = a.multiply(v).add(u).mod(p);
+ u = tmp;
+ }
+ }
+ squareRoot = u;
+ }
+ // The methods used to compute the square root only guarantee a correct result if the
+ // preconditions (i.e. p prime and x is a square) are satisfied. Otherwise the value is
+ // undefined. Hence, it is important to verify that squareRoot is indeed a square root.
+ if (squareRoot != null && squareRoot.multiply(squareRoot).mod(p).compareTo(x) != 0) {
+ throw new GeneralSecurityException("Could not find square root");
+ }
+ return squareRoot;
+ }
+
+ /**
+ * Returns the modulus of the field used by the curve specified in ecParams.
+ *
+ * @param curve must be a prime order elliptic curve
+ * @return the order of the finite field over which curve is defined.
+ */
+ public static BigInteger getModulus(EllipticCurve curve) throws GeneralSecurityException {
+ java.security.spec.ECField field = curve.getField();
+ if (field instanceof java.security.spec.ECFieldFp) {
+ return ((java.security.spec.ECFieldFp) field).getP();
+ } else {
+ throw new GeneralSecurityException("Only curves over prime order fields are supported");
+ }
+ }
+
+ /**
+ * Returns the size of an element of the field over which the curve is defined.
+ *
+ * @param curve must be a prime order elliptic curve
+ * @return the size of an element in bits
+ */
+ public static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException {
+ return getModulus(curve).subtract(BigInteger.ONE).bitLength();
+ }
+
+ /**
+ * Returns the size of an element of the field over which the curve is defined.
+ *
+ * @param curve must be a prime order elliptic curve
+ * @return the size of an element in bytes.
+ */
+ public static int fieldSizeInBytes(EllipticCurve curve) throws GeneralSecurityException {
+ return (fieldSizeInBits(curve) + 7) / 8;
+ }
+
+ /**
+ * Checks that a point is on a given elliptic curve. This method implements the partial public key
+ * validation routine from Section 5.6.2.6 of NIST SP 800-56A
+ * http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf A partial
+ * public key validation is sufficient for curves with cofactor 1. See Section B.3 of
+ * http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf The point validations above are
+ * taken from recommendations for ECDH, because parameter checks in ECDH are much more important
+ * than for the case of ECDSA. Performing this test for ECDSA keys is mainly a sanity check.
+ *
+ * @param point the point that needs verification
+ * @param ec the elliptic curve. This must be a curve over a prime order field.
+ * @throws GeneralSecurityException if the field is binary or if the point is not on the curve.
+ */
+ public static void checkPointOnCurve(ECPoint point, EllipticCurve ec)
+ throws GeneralSecurityException {
+ BigInteger p = getModulus(ec);
+ BigInteger x = point.getAffineX();
+ BigInteger y = point.getAffineY();
+ if (x == null || y == null) {
+ throw new GeneralSecurityException("point is at infinity");
+ }
+ // Check 0 <= x < p and 0 <= y < p.
+ if (x.signum() == -1 || x.compareTo(p) != -1) {
+ throw new GeneralSecurityException("x is out of range");
+ }
+ if (y.signum() == -1 || y.compareTo(p) != -1) {
+ throw new GeneralSecurityException("y is out of range");
+ }
+ // Check y^2 == x^3 + a x + b (mod p)
+ BigInteger lhs = y.multiply(y).mod(p);
+ BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p);
+ if (!lhs.equals(rhs)) {
+ throw new GeneralSecurityException("Point is not on curve");
+ }
+ }
+
+ /**
+ * Checks a public key. I.e. this checks that the point defining the public key is on the curve.
+ *
+ * @param key must be a key defined over a curve using a prime order field.
+ * @throws GeneralSecurityException if the key is not valid.
+ */
+ public static void checkPublicKey(ECPublicKey key) throws GeneralSecurityException {
+ checkPointOnCurve(key.getW(), key.getParams().getCurve());
+ }
+
+ /**
+ * Decompress a point
+ *
+ * @param x The x-coordinate of the point
+ * @param bit0 true if the least significant bit of y is set.
+ * @param ecParams contains the curve of the point. This must be over a prime order field.
+ */
+ public static ECPoint getPoint(BigInteger x, boolean bit0, ECParameterSpec ecParams)
+ throws GeneralSecurityException {
+ EllipticCurve ec = ecParams.getCurve();
+ ECField field = ec.getField();
+ if (!(field instanceof ECFieldFp)) {
+ throw new GeneralSecurityException("Only curves over prime order fields are supported");
+ }
+ BigInteger p = ((java.security.spec.ECFieldFp) field).getP();
+ if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) {
+ throw new GeneralSecurityException("x is out of range");
+ }
+ // Compute rhs == x^3 + a x + b (mod p)
+ BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p);
+ BigInteger y = modSqrt(rhs, p);
+ if (bit0 != y.testBit(0)) {
+ y = p.subtract(y).mod(p);
+ }
+ return new ECPoint(x, y);
+ }
+
+ /**
+ * Decompress a point on an elliptic curve.
+ *
+ * @param bytes The compressed point. Its representation is z || x where z is 2+lsb(y) and x is
+ * using a unsigned fixed length big-endian representation.
+ * @param ecParams the specification of the curve. Only Weierstrass curves over prime order fields
+ * are implemented.
+ */
+ public static ECPoint decompressPoint(byte[] bytes, ECParameterSpec ecParams)
+ throws GeneralSecurityException {
+ EllipticCurve ec = ecParams.getCurve();
+ ECField field = ec.getField();
+ if (!(field instanceof ECFieldFp)) {
+ throw new GeneralSecurityException("Only curves over prime order fields are supported");
+ }
+ BigInteger p = ((java.security.spec.ECFieldFp) field).getP();
+ int expectedLength = 1 + (p.bitLength() + 7) / 8;
+ if (bytes.length != expectedLength) {
+ throw new GeneralSecurityException("compressed point has wrong length");
+ }
+ boolean lsb;
+ switch (bytes[0]) {
+ case 2:
+ lsb = false;
+ break;
+ case 3:
+ lsb = true;
+ break;
+ default:
+ throw new GeneralSecurityException("Invalid format");
+ }
+ BigInteger x = new BigInteger(1, Arrays.copyOfRange(bytes, 1, bytes.length));
+ if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) {
+ throw new GeneralSecurityException("x is out of range");
+ }
+ // Compute rhs == x^3 + a x + b (mod p)
+ BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p);
+ BigInteger y = modSqrt(rhs, p);
+ if (lsb != y.testBit(0)) {
+ y = p.subtract(y).mod(p);
+ }
+ return new ECPoint(x, y);
+ }
+
+ /**
+ * Returns a weak public key of order 3 such that the public key point is on the curve specified
+ * in ecParams. This method is used to check ECC implementations for missing step in the
+ * verification of the public key. E.g. implementations of ECDH must verify that the public key
+ * contains a point on the curve as well as public and secret key are using the same curve.
+ *
+ * @param ecParams the parameters of the key to attack. This must be a curve in Weierstrass form
+ * over a prime order field.
+ * @return a weak EC group with a genrator of order 3.
+ */
+ public static ECPublicKeySpec getWeakPublicKey(ECParameterSpec ecParams)
+ throws GeneralSecurityException {
+ EllipticCurve curve = ecParams.getCurve();
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(ecParams);
+ BigInteger p = getModulus(curve);
+ BigInteger three = new BigInteger("3");
+ while (true) {
+ // Generate a point on the original curve
+ KeyPair keyPair = keyGen.generateKeyPair();
+ ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
+ ECPoint w = pub.getW();
+ BigInteger x = w.getAffineX();
+ BigInteger y = w.getAffineY();
+ // Find the curve parameters a,b such that 3*w = infinity.
+ // This is the case if the following equations are satisfied:
+ // 3x == l^2 (mod p)
+ // l == (3x^2 + a) / 2*y (mod p)
+ // y^2 == x^3 + ax + b (mod p)
+ BigInteger l;
+ try {
+ l = modSqrt(x.multiply(three), p);
+ } catch (GeneralSecurityException ex) {
+ continue;
+ }
+ BigInteger xSqr = x.multiply(x).mod(p);
+ BigInteger a = l.multiply(y.add(y)).subtract(xSqr.multiply(three)).mod(p);
+ BigInteger b = y.multiply(y).subtract(x.multiply(xSqr.add(a))).mod(p);
+ EllipticCurve newCurve = new EllipticCurve(curve.getField(), a, b);
+ // Just a sanity check.
+ checkPointOnCurve(w, newCurve);
+ // Cofactor and order are of course wrong.
+ ECParameterSpec spec = new ECParameterSpec(newCurve, w, p, 1);
+ return new ECPublicKeySpec(w, spec);
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/OpenJDKAllTests.java b/java/com/google/security/wycheproof/OpenJDKAllTests.java
new file mode 100644
index 0000000..a2b3b06
--- /dev/null
+++ b/java/com/google/security/wycheproof/OpenJDKAllTests.java
@@ -0,0 +1,34 @@
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Tests for OpenJDK's providers: SunJCE, SunEC, etc.
+ * OpenJDKAllTests runs all tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class
+})
+@Provider(ProviderType.OPENJDK)
+public final class OpenJDKAllTests {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyOpenJDKProviders();
+ }
+}
diff --git a/java/com/google/security/wycheproof/OpenJDKTest.java b/java/com/google/security/wycheproof/OpenJDKTest.java
new file mode 100644
index 0000000..b326fef
--- /dev/null
+++ b/java/com/google/security/wycheproof/OpenJDKTest.java
@@ -0,0 +1,36 @@
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Tests for OpenJDK's providers: SunJCE, SunEC, etc.
+ * OpenJDKTest excludes slow tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class
+})
+@Provider(ProviderType.OPENJDK)
+@Fast
+public final class OpenJDKTest {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyOpenJDKProviders();
+ }
+}
diff --git a/java/com/google/security/wycheproof/ProviderIndependentTest.java b/java/com/google/security/wycheproof/ProviderIndependentTest.java
new file mode 100644
index 0000000..931fc64
--- /dev/null
+++ b/java/com/google/security/wycheproof/ProviderIndependentTest.java
@@ -0,0 +1,26 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/** Provider independent tests */
+@RunWith(Suite.class)
+@SuiteClasses({BigIntegerTest.class})
+public final class ProviderIndependentTest {}
diff --git a/java/com/google/security/wycheproof/RandomUtil.java b/java/com/google/security/wycheproof/RandomUtil.java
new file mode 100644
index 0000000..388c272
--- /dev/null
+++ b/java/com/google/security/wycheproof/RandomUtil.java
@@ -0,0 +1,185 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.util.Random;
+
+/**
+ * A collection of utilities for testing random number generators. So far this util simply checks
+ * that random numbers are not generated by java.util.Random. Eventually we plan to add detection
+ * for other random number generators too.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+public class RandomUtil {
+ // Constants for java.util.Random;
+ static final long A = 0x5DEECE66DL;
+ static final long A_INVERSE = 246154705703781L;
+ static final long C = 0xBL;
+
+ /** Given a state of a java.util.Random object compute the next state. */
+ protected static long nextState(long seed) {
+ return (seed * A + C) & ((1L << 48) - 1);
+ }
+
+ /** Give the state after stepping java.util.Random n times. */
+ protected static long step(long seed, long n) {
+ long a = A;
+ long c = C;
+ n = n & 0xffffffffffffL;
+ while (n != 0) {
+ if ((n & 1) == 1) {
+ seed = seed * a + c;
+ }
+ c = c * (a + 1);
+ a = a * a;
+ n = n >> 1;
+ }
+ return seed & 0xffffffffffffL;
+ }
+
+ /** Given a state of a java.util.Random object compute the previous state. */
+ protected static long previousState(long seed) {
+ return ((seed - C) * A_INVERSE) & ((1L << 48) - 1);
+ }
+
+ /** Computes a seed that would initialize a java.util.Random object with a given state. */
+ protected static long getSeedForState(long seed) {
+ return seed ^ A;
+ }
+
+ protected static long getStateForSeed(long seed) {
+ return (seed ^ A) & 0xffffffffffffL;
+ }
+
+ /**
+ * Given two subsequent outputs x0 and x1 from java.util.Random this function computes the
+ * internal state of java.util.Random after returning x0 or returns -1 if no such state exists.
+ */
+ protected static long getState(int x0, int x1) {
+ long mask = (1L << 48) - 1;
+ long multiplier = A;
+ // The state of the random number generator after returning x0 is
+ // l0 + eps for some 0 <= eps < 2**16.
+ long l0 = ((long) x0 << 16) & mask;
+ // The state of the random number generator after returning x1 is
+ // l1 + delta for some 0 <= delta < 2**16.
+ long l1 = ((long) x1 << 16) & mask;
+ // We have l1 + delta = (l0 + eps)*multiplier + 0xBL (mod 2**48).
+ // This allows to find an upper bound w for eps * multiplier mod 2**48
+ // by assuming delta = 2**16-1.
+ long w = (l1 - l0 * multiplier + 65535L - 0xBL) & mask;
+ // The reduction eps * multiplier mod 2**48 only cuts off at most 3 bits.
+ // Hence a simple search is sufficient. The maximal number of loops is 6.
+ for (long em = w; em < (multiplier << 16); em += 1L << 48) {
+ // If the high order bits of em are guessed correctly then
+ // em == eps * multiplier + 65535 - delta.
+ long eps = em / multiplier;
+ long state0 = l0 + eps;
+ long state1 = nextState(state0);
+ if ((state1 & 0xffffffff0000L) == l1) {
+ return state0;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find a seed such that this integer is the result of
+ *
+ * <pre>{@code
+ * Random rand = new Random();
+ * rand.setSeed(seed);
+ * return new BigInteger(k, rand);
+ * }</pre>
+ *
+ * where k is max(64, x.BitLength());
+ *
+ * <p>Returns -1 if no such seed exists.
+ */
+ // TODO(bleichen): We want to detect cases where some of the bits
+ // (i.e. most significant bits or least significant bits have
+ // been modified. Often this happens during the generation
+ // of primes or other things.
+ // TODO(bleichen): This method is incomplete.
+ protected static long getSeedFor(java.math.BigInteger x) {
+ byte[] bytes = x.toByteArray();
+ if (bytes.length == 0) {
+ return -1;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(8);
+ int offset = bytes[0] == 0 ? 1 : 0;
+ if (bytes.length - offset < 8) {
+ int size = bytes.length - offset;
+ buffer.position(8 - size);
+ buffer.put(bytes, offset, size);
+ } else {
+ buffer.put(bytes, offset, 8);
+ }
+ buffer.flip();
+ buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
+ int x0 = buffer.getInt();
+ int x1 = buffer.getInt();
+ long state = getState(x0, x1);
+ if (state == -1) {
+ return -1;
+ }
+ return getSeedForState(previousState(state));
+ }
+
+ /** Attempts to find a seed such that it generates the prime p. Returns -1 if no seed is found. */
+ static long getSeedForPrime(BigInteger p) {
+ int confidence = 64;
+ Random rand = new Random();
+ int size = p.bitLength();
+ // Prime generation often sets the most significant bit.
+ // Hence, clearing the most significant bit can help to find
+ // the seed used for the prime generation.
+ for (BigInteger x : new BigInteger[] {p, p.clearBit(size - 1)}) {
+ long seed = getSeedFor(x);
+ if (seed != -1) {
+ rand.setSeed(seed);
+ BigInteger q = new BigInteger(size, confidence, rand);
+ if (q.equals(p)) {
+ return seed;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks whether p is a random prime. A prime generated with a secure random number generator
+ * passes with probability > 1-2^{-32}. No checks are performed for primes smaller than 96 bits.
+ *
+ * @throws GeneralSecurityException if the prime was generated using java.util.Random
+ */
+ static void checkPrime(BigInteger p) throws GeneralSecurityException {
+ // We can't reliably detect java.util.Random for small primes.
+ if (p.bitLength() < 96) {
+ return;
+ }
+ long seed = getSeedForPrime(p);
+ if (seed != -1) {
+ throw new GeneralSecurityException(
+ "java.util.Random with seed " + seed + " was likely used to generate prime");
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/SpongyCastleAllTests.java b/java/com/google/security/wycheproof/SpongyCastleAllTests.java
new file mode 100644
index 0000000..5566827
--- /dev/null
+++ b/java/com/google/security/wycheproof/SpongyCastleAllTests.java
@@ -0,0 +1,54 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * SpongyCastleTest excludes {@code @SlowTest} tests.
+ * SpongyCastleAllTests runs all tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesEaxTest.class,
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DhiesTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ EciesTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class,
+})
+@Provider(ProviderType.SPONGY_CASTLE)
+public final class SpongyCastleAllTests {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyThisProvider(new BouncyCastleProvider());
+ }
+}
diff --git a/java/com/google/security/wycheproof/SpongyCastleTest.java b/java/com/google/security/wycheproof/SpongyCastleTest.java
new file mode 100644
index 0000000..73c8ca1
--- /dev/null
+++ b/java/com/google/security/wycheproof/SpongyCastleTest.java
@@ -0,0 +1,56 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Spongy Castle is a Bouncy Castle clone with a few changes to make it work on Android.
+ * SpongyCastleTest excludes {@code @SlowTest} tests.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesEaxTest.class,
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DhiesTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ EciesTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class,
+})
+@Provider(ProviderType.SPONGY_CASTLE)
+@Fast
+public final class SpongyCastleTest {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ TestUtil.installOnlyThisProvider(new BouncyCastleProvider());
+ }
+}
diff --git a/java/com/google/security/wycheproof/TestUtil.java b/java/com/google/security/wycheproof/TestUtil.java
new file mode 100644
index 0000000..ae21adc
--- /dev/null
+++ b/java/com/google/security/wycheproof/TestUtil.java
@@ -0,0 +1,99 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.nio.ByteBuffer;
+import java.security.Provider;
+import java.security.Security;
+
+/** Test utilities */
+public class TestUtil {
+
+ public static String bytesToHex(byte[] bytes) {
+ // bytesToHex is used to convert output from Cipher.
+ // cipher.update can return null, which is equivalent to returning
+ // no plaitext rsp. ciphertext.
+ if (bytes == null) {
+ return "";
+ }
+ String chars = "0123456789abcdef";
+ StringBuilder result = new StringBuilder(2 * bytes.length);
+ for (byte b : bytes) {
+ // convert to unsigned
+ int val = b & 0xff;
+ result.append(chars.charAt(val / 16));
+ result.append(chars.charAt(val % 16));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns a hexadecimal representation of the bytes written to ByteBuffer (i.e. all the bytes
+ * before position()).
+ */
+ public static String byteBufferToHex(ByteBuffer buffer) {
+ ByteBuffer tmp = buffer.duplicate();
+ tmp.flip();
+ byte[] bytes = new byte[tmp.remaining()];
+ tmp.get(bytes);
+ return bytesToHex(bytes);
+ }
+
+ public static byte[] hexToBytes(String hex) throws IllegalArgumentException {
+ if (hex.length() % 2 != 0) {
+ throw new IllegalArgumentException("Expected a string of even length");
+ }
+ int size = hex.length() / 2;
+ byte[] result = new byte[size];
+ for (int i = 0; i < size; i++) {
+ int hi = Character.digit(hex.charAt(2 * i), 16);
+ int lo = Character.digit(hex.charAt(2 * i + 1), 16);
+ if ((hi == -1) || (lo == -1)) {
+ throw new IllegalArgumentException("input is not hexadecimal");
+ }
+ result[i] = (byte) (16 * hi + lo);
+ }
+ return result;
+ }
+
+ public static void installOnlyThisProvider(Provider provider) {
+ for (Provider p : Security.getProviders()) {
+ Security.removeProvider(p.getName());
+ }
+ Security.insertProviderAt(provider, 1);
+ }
+
+ public static void installOnlyOpenJDKProviders() throws Exception {
+ for (Provider p : Security.getProviders()) {
+ Security.removeProvider(p.getName());
+ }
+ installOpenJDKProvider("com.sun.net.ssl.internal.ssl.Provider");
+ installOpenJDKProvider("com.sun.crypto.provider.SunJCE");
+ installOpenJDKProvider("com.sun.security.sasl.Provider");
+ installOpenJDKProvider("org.jcp.xml.dsig.internal.dom.XMLDSigRI");
+ installOpenJDKProvider("sun.security.ec.SunEC");
+ installOpenJDKProvider("sun.security.jgss.SunProvider");
+ installOpenJDKProvider("sun.security.provider.Sun");
+ installOpenJDKProvider("sun.security.rsa.SunRsaSign");
+ installOpenJDKProvider("sun.security.smartcardio.SunPCSC");
+ }
+
+ private static void installOpenJDKProvider(String className) throws Exception {
+ Provider provider = (Provider) Class.forName(className).getConstructor().newInstance();
+ Security.insertProviderAt(provider, 1);
+ }
+}
diff --git a/java/com/google/security/wycheproof/WycheproofRunner.java b/java/com/google/security/wycheproof/WycheproofRunner.java
new file mode 100644
index 0000000..e4da431
--- /dev/null
+++ b/java/com/google/security/wycheproof/WycheproofRunner.java
@@ -0,0 +1,206 @@
+/**
+ * @license
+ * Copyright 2013 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * <p>A custom JUnit4 runner that, with annotations, allows choosing tests to run on a specific
+ * provider. To use it, annotate a runner class with {@code RunWith(WycheproofRunner.class)}, and
+ * {@code SuiteClasses({AesGcmTest.class, ...})}. When you run this class, it will run all the tests
+ * in all the suite classes.
+ *
+ * <p>To exclude certain tests, a runner class should be annotated with {@code @Provider} which
+ * indicates the target provider. Test exclusion is defined as follows:
+ * <ul>@Fast test runners skip @SlowTest test functions.
+ * <ul>@Presubmit test runners skip @NoPresubmitTest test functions.
+ * <ul>All test runners skip @ExcludedTest test functions.
+ *
+ * @author thaidn@google.com (Thai Duong)
+ */
+public class WycheproofRunner extends Suite {
+
+ /** List of supported providers. */
+ public enum ProviderType {
+ BOUNCY_CASTLE,
+ CONSCRYPT,
+ OPENJDK,
+ SPONGY_CASTLE,
+ }
+
+ // Annotations for test runners.
+
+ /**
+ * Annotation to specify the target provider of a test runner.
+ *
+ * <p>Usage: @Provider(ProviderType.BOUNCY_CASTLE)
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ public @interface Provider {
+ ProviderType value();
+ }
+
+ /**
+ * Annotation to specify presubmit test runners that exclude {@code @NoPresubmitTets} tests.
+ *
+ * <p>Usage: @Presubmit(ProviderType.BOUNCY_CASTLE)
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ public @interface Presubmit {}
+
+ /**
+ * Annotation to specify fast test runners that exclude {@code @SlowTest} tests.
+ *
+ * <p>Usage: @Fast
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ public @interface Fast {}
+
+ // Annotations for test functions
+
+ /**
+ * Tests that take too much time to run, should be excluded from TAP and wildcard target patterns
+ * like:..., :*, or :all.
+ *
+ * <p>Usage: @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ...})
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ public @interface SlowTest {
+ ProviderType[] providers();
+ }
+
+ /**
+ * Tests that should be excluded from presubmit checks on specific providers.
+ *
+ * <p>Usage: @NoPresubmitTest(
+ * providers = {ProviderType.BOUNCY_CASTLE, ...},
+ * bugs = {"b/123456789"}
+ * )
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD, ElementType.FIELD})
+ public @interface NoPresubmitTest {
+ /** List of providers that this test method should not run as presubmit check. */
+ ProviderType[] providers();
+
+ /** List of blocking bugs (and comments). */
+ String[] bugs();
+ }
+
+ /**
+ * Annotation to specify test functions that should be excluded on specific providers.
+ *
+ * <p>Usage: @ExcludedTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.OPENJDK})
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ public @interface ExcludedTest {
+ ProviderType[] providers();
+ String comment();
+ }
+
+ /**
+ * Custom filter to exclude certain test functions.
+ *
+ */
+ public static class ExcludeTestFilter extends Filter {
+
+ Class<?> runnerClass;
+ Provider targetProvider;
+ Fast fast;
+ Presubmit presubmit;
+
+ public ExcludeTestFilter(Class<?> runnerClass) {
+ this.runnerClass = runnerClass;
+ this.targetProvider = runnerClass.getAnnotation(Provider.class);
+ this.fast = runnerClass.getAnnotation(Fast.class);
+ this.presubmit = runnerClass.getAnnotation(Presubmit.class);
+ }
+
+ @Override
+ public String describe() {
+ return "exclude certain tests on specific providers";
+ }
+
+ @Override
+ public boolean shouldRun(Description description) {
+ return isOkayToRunTest(description);
+ }
+
+ private boolean isOkayToRunTest(Description description) {
+ if (targetProvider == null) {
+ // Run all test functions if the test runner is not annotated with {@code @Provider}.
+ return true;
+ }
+ // Skip @ExcludedTest tests
+ ExcludedTest excludedTest = description.getAnnotation(ExcludedTest.class);
+ if (excludedTest != null
+ && Arrays.asList(excludedTest.providers()).contains(targetProvider.value())) {
+ return false;
+ }
+
+ // If the runner class is annotated with @Presubmit, skip non-presubmit tests
+ if (presubmit != null) {
+ NoPresubmitTest ignoreOn = description.getAnnotation(NoPresubmitTest.class);
+ if (ignoreOn != null
+ && Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
+ return false;
+ }
+ }
+
+ // If the runner class is annotated with @Fast, skip slow tests
+ if (fast != null) {
+ SlowTest ignoreOn = description.getAnnotation(SlowTest.class);
+ if (ignoreOn != null
+ && Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
+ return false;
+ }
+ }
+
+ // run everything else
+ return true;
+ }
+ }
+
+ /** Required constructor: called by JUnit reflectively. */
+ public WycheproofRunner(Class<?> runnerClass, RunnerBuilder builder) throws InitializationError {
+ super(runnerClass, builder);
+ addFilter(new ExcludeTestFilter(runnerClass));
+ }
+
+ private void addFilter(Filter filter) {
+ try {
+ filter(filter);
+ } catch (NoTestsRemainException ex) {
+ System.out.println("No tests remain exception: " + ex);
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/AesEaxTest.java b/java/com/google/security/wycheproof/testcases/AesEaxTest.java
new file mode 100644
index 0000000..a40f1cc
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/AesEaxTest.java
@@ -0,0 +1,268 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(bleichen):
+// - So far only 16 byte tags are tested.
+// Tested providers:
+// BC : ok
+// BC uses a 64-bit default for tags. This is not such a big
+// problem as with AES-GCM, since the tag gives 64 bit strength.
+
+package com.google.security.wycheproof;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import junit.framework.TestCase;
+
+/** AES-EAX tests */
+public class AesEaxTest extends TestCase {
+
+ /** Test vectors */
+ public static class EaxTestVector {
+ final byte[] pt;
+ final byte[] aad;
+ final byte[] ct;
+ final String ptHex;
+ final String ctHex;
+ final GCMParameterSpec parameters;
+ final SecretKeySpec key;
+
+ public EaxTestVector(
+ String message, String keyMaterial, String nonce, String aad, String ciphertext) {
+ this.ptHex = message;
+ this.pt = TestUtil.hexToBytes(message);
+ this.aad = TestUtil.hexToBytes(aad);
+ this.ct = TestUtil.hexToBytes(ciphertext);
+ this.ctHex = ciphertext;
+ // Ugly hack from
+ // https://github.com/bcgit/bc-java/blob/master/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java
+ // Apparently, one way to specify the tag length is to use GCMParameterSpec.
+ // BouncyCastle is using a 64-bit tag by default.
+ // So far all test vectors use a 128 bit tag.
+ this.parameters = new GCMParameterSpec(128, TestUtil.hexToBytes(nonce));
+ this.key = new SecretKeySpec(TestUtil.hexToBytes(keyMaterial), "AES");
+ }
+ };
+
+ private static final EaxTestVector[] EAX_TEST_VECTOR = {
+ // Test vectors from
+ // http://csrc.nist.gov/groups/ST/toolkit/BCM/modes_development.html
+ // TODO(bleichen): Check if we can include test cases from NIST and
+ // republish.
+ new EaxTestVector(
+ "",
+ "233952dee4d5ed5f9b9c6d6ff80ff478",
+ "62ec67f9c3a4a407fcb2a8c49031a8b3",
+ "6bfb914fd07eae6b",
+ "e037830e8389f27b025a2d6527e79d01"),
+ new EaxTestVector(
+ "f7fb",
+ "91945d3f4dcbee0bf45ef52255f095a4",
+ "becaf043b0a23d843194ba972c66debd",
+ "fa3bfd4806eb53fa",
+ "19dd5c4c9331049d0bdab0277408f67967e5"),
+ new EaxTestVector(
+ "1a47cb4933",
+ "01f74ad64077f2e704c0f60ada3dd523",
+ "70c3db4f0d26368400a10ed05d2bff5e",
+ "234a3463c1264ac6",
+ "d851d5bae03a59f238a23e39199dc9266626c40f80"),
+ new EaxTestVector(
+ "481c9e39b1",
+ "d07cf6cbb7f313bdde66b727afd3c5e8",
+ "8408dfff3c1a2b1292dc199e46b7d617",
+ "33cce2eabff5a79d",
+ "632a9d131ad4c168a4225d8e1ff755939974a7bede"),
+ new EaxTestVector(
+ "40d0c07da5e4",
+ "35b6d0580005bbc12b0587124557d2c2",
+ "fdb6b06676eedc5c61d74276e1f8e816",
+ "aeb96eaebe2970e9",
+ "071dfe16c675cb0677e536f73afe6a14b74ee49844dd"),
+ new EaxTestVector(
+ "4de3b35c3fc039245bd1fb7d",
+ "bd8e6e11475e60b268784c38c62feb22",
+ "6eac5c93072d8e8513f750935e46da1b",
+ "d4482d1ca78dce0f",
+ "835bb4f15d743e350e728414abb8644fd6ccb86947c5e10590210a4f"),
+ new EaxTestVector(
+ "8b0a79306c9ce7ed99dae4f87f8dd61636",
+ "7c77d6e813bed5ac98baa417477a2e7d",
+ "1a8c98dcd73d38393b2bf1569deefc19",
+ "65d2017990d62528",
+ "02083e3979da014812f59f11d52630da30137327d10649b0aa6e1c181db617d7" + "f2"),
+ new EaxTestVector(
+ "1bda122bce8a8dbaf1877d962b8592dd2d56",
+ "5fff20cafab119ca2fc73549e20f5b0d",
+ "dde59b97d722156d4d9aff2bc7559826",
+ "54b9f04e6a09189a",
+ "2ec47b2c4954a489afc7ba4897edcdae8cc33b60450599bd02c96382902aef7f" + "832a"),
+ new EaxTestVector(
+ "6cf36720872b8513f6eab1a8a44438d5ef11",
+ "a4a4782bcffd3ec5e7ef6d8c34a56123",
+ "b781fcf2f75fa5a8de97a9ca48e522ec",
+ "899a175897561d7e",
+ "0de18fd0fdd91e7af19f1d8ee8733938b1e8e7f6d2231618102fdb7fe55ff199" + "1700"),
+ new EaxTestVector(
+ "ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7",
+ "8395fcf1e95bebd697bd010bc766aac3",
+ "22e7add93cfc6393c57ec0b3c17d6b44",
+ "126735fcc320d25a",
+ "cb8920f87a6c75cff39627b56e3ed197c552d295a7cfc46afc253b4652b1af37" + "95b124ab6e"),
+ // The tests are self generated.
+ //
+ // Some test vectors for counter overflow:
+ // Initial counter value == 2^128-1
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "3c8cc2970a008f75cc5beae2847258c2",
+ "",
+ "3c441f32ce07822364d7a2990e50bb13d7b02a26969e4a937e5e9073b0d9c968"
+ + "db90bdb3da3d00afd0fc6a83551da95e"),
+ // counter value overflows at 64-bit boundary
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "aef03d00598494e9fb03cd7d8b590866",
+ "",
+ "d19ac59849026a91aa1b9aec29b11a202a4d739fd86c28e3ae3d588ea21d70c6"
+ + "c30f6cd9202074ed6e2a2a360eac8c47"),
+ // no counter overflow, but the 64 most significant bits are set.
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "55d12511c696a80d0514d1ffba49cada",
+ "",
+ "2108558ac4b2c2d5cc66cea51d6210e046177a67631cd2dd8f09469733acb517"
+ + "fc355e87a267be3ae3e44c0bf3f99b2b"),
+ // counter value overflows at 32-bit boundary
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "79422ddd91c4eee2deaef1f968305304",
+ "",
+ "4d2c1524ca4baa4eefcce6b91b227ee83abaff8105dcafa2ab191f5df2575035"
+ + "e2c865ce2d7abdac024c6f991a848390"),
+ // no counter overflow, but bits 32-64 and 96-128 are set.
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "0af5aa7a7676e28306306bcd9bf2003a",
+ "",
+ "8eb01e62185d782eb9287a341a6862ac5257d6f9adc99ee0a24d9c22b3e9b38a"
+ + "39c339bc8a74c75e2c65c6119544d61e"),
+ // no counter overflow, lower 64 bits are 2^63-1
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111",
+ "000102030405060708090a0b0c0d0e0f",
+ "af5a03ae7edd73471bdcdfac5e194a60",
+ "",
+ "94c5d2aca6dbbce8c24513a25e095c0e54a942860d327a222a815cc713b163b4"
+ + "f50b30304e45c9d411e8df4508a98612"),
+ // counter overflow between block 2 and block 3.
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111"
+ + "2222222222222222222222222222222233333333333333333333333333333333",
+ "000102030405060708090a0b0c0d0e0f",
+ "b37087680f0edd5a52228b8c7aaea664",
+ "",
+ "3bb6173e3772d4b62eef37f9ef0781f360b6c74be3bf6b371067bc1b090d9d66"
+ + "22a1fbec6ac471b3349cd4277a101d40890fbf27dfdcd0b4e3781f9806daabb6"
+ + "a0498745e59999ddc32d5b140241124e"),
+ // no counter overflow, the lower 64 bits are 2^63-4.
+ new EaxTestVector(
+ "0000000000000000000000000000000011111111111111111111111111111111"
+ + "2222222222222222222222222222222233333333333333333333333333333333"
+ + "44444444444444444444444444444444",
+ "000102030405060708090a0b0c0d0e0f",
+ "4f802da62a384555a19bc2b382eb25af",
+ "",
+ "e9b0bb8857818ce3201c3690d21daa7f264fb8ee93cc7a4674ea2fc32bf182fb"
+ + "2a7e8ad51507ad4f31cefc2356fe7936a7f6e19f95e88fdbf17620916d3a6f3d"
+ + "01fc17d358672f777fd4099246e436e167910be744b8315ae0eb6124590c5d8b"),
+ // 192-bit keys
+ new EaxTestVector(
+ "",
+ "03dd258601c1d4872a52b27892db0356911b2df1436dc7f4",
+ "723cb2022102113018dcd2d204022114",
+ "",
+ "c472b1c6c22b4f2b7e02409499aa2ade"),
+ new EaxTestVector(
+ "abcdef",
+ "03dd258601c1d4872a52b27892db0356911b2df1436dc7f4",
+ "025f3d2286c143976412022102696708231208",
+ "8917328de211",
+ "520f4f2cf1b893ae3ba8ecbac3a08ea57de2cd"),
+ new EaxTestVector(
+ "1111111111111111111111111111111122222222222222222222222222222222",
+ "0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
+ "000102030405060708090a0b0c0d0e0f1a1b1c1d",
+ "77922d34e452e0a40962873d22901dd22ad1c303",
+ "5917879b9fa85f4007b7bd0cd46f067d5a7bf287f19dfcc5475c95a4acce520a"
+ + "4c5df804bc091a3b5d6c838b7e494571"),
+ // 256-bit keys
+ new EaxTestVector(
+ "",
+ "0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
+ "696708231208",
+ "",
+ "7c8f86f837a4f72c574678d92f637f07"),
+ new EaxTestVector(
+ "abcdef",
+ "0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
+ "696708231208",
+ "8917328de211",
+ "12486c87bf9a7f22fa65a9493ec0f57f8070f5"),
+ new EaxTestVector(
+ "1111111111111111111111111111111122222222222222222222222222222222",
+ "0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
+ "000102030405060708090a0b0c0d0e0f1a1b1c1d",
+ "92d3e42e0409273291d2dc034450",
+ "5917879b9fa85f4007b7bd0cd46f067d5a7bf287f19dfcc5475c95a4acce520a"
+ + "e632946e4999be20159977431bef0454"),
+ };
+
+ public void testEax() throws Exception {
+ for (EaxTestVector test : EAX_TEST_VECTOR) {
+ Cipher cipher = Cipher.getInstance("AES/EAX/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ byte[] ct = cipher.doFinal(test.pt);
+ assertEquals(test.ctHex, TestUtil.bytesToHex(ct));
+ }
+ }
+
+ public void testLateUpdateAAD() throws Exception {
+ for (EaxTestVector test : EAX_TEST_VECTOR) {
+ Cipher cipher = Cipher.getInstance("AES/EAX/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ byte[] c0 = cipher.update(test.pt);
+ try {
+ cipher.updateAAD(test.aad);
+ } catch (java.lang.IllegalStateException ex) {
+ // Typically one should pass the AAD in first.
+ // Hence it is OK to get this exception.
+ // For example, this is the behaviour of SUNJce.
+ continue;
+ }
+ byte[] c1 = cipher.doFinal();
+ String result = TestUtil.bytesToHex(c0) + TestUtil.bytesToHex(c1);
+ assertEquals(test.ctHex, result);
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/AesGcmTest.java b/java/com/google/security/wycheproof/testcases/AesGcmTest.java
new file mode 100644
index 0000000..c3c3dad
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/AesGcmTest.java
@@ -0,0 +1,405 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import javax.crypto.Cipher;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import junit.framework.TestCase;
+
+// TODO(bleichen):
+// - For EAX I was able to derive some special cases by inverting OMAC.
+// Not sure if that is possible here.
+// - Gcm used to skip the tag verification in BouncyCastle when using ByteBuffers.
+// test this.
+// - Other Bytebuffer tests: Buffers with offset, Readonly buffers
+// - The SUNJce provider requires tags that are at least 96 bits long.
+// It would make sense to require this for all providers and add a test.
+// - conscrypt only allows 12 byte IVs.
+/**
+ * Testing AES-GCM
+ *
+ * <p>Other tests using AES-GCM are: CipherInputStreamTest.java CipherOuputStreamTest.java
+ */
+public class AesGcmTest extends TestCase {
+
+ /** Test vectors */
+ public static class GcmTestVector {
+ final byte[] pt;
+ final byte[] aad;
+ final byte[] ct;
+ final String ptHex;
+ final String ctHex;
+ final GCMParameterSpec parameters;
+ final SecretKeySpec key;
+
+ public GcmTestVector(
+ String message,
+ String keyMaterial,
+ String nonce,
+ String aad,
+ String ciphertext,
+ String tag) {
+ this.ptHex = message;
+ this.pt = TestUtil.hexToBytes(message);
+ this.aad = TestUtil.hexToBytes(aad);
+ this.ct = TestUtil.hexToBytes(ciphertext + tag);
+ this.ctHex = ciphertext + tag;
+ int tagLength = 4 * tag.length();
+ this.parameters = new GCMParameterSpec(tagLength, TestUtil.hexToBytes(nonce));
+ this.key = new SecretKeySpec(TestUtil.hexToBytes(keyMaterial), "AES");
+ }
+ };
+
+ // default, used for BouncyCastle
+ private static final GcmTestVector[] DEFAULT_GCM_TEST_VECTORS = {
+ new GcmTestVector(
+ "001d0c231287c1182784554ca3a21908",
+ "5b9604fe14eadba931b0ccf34843dab9",
+ "028318abc1824029138141a2",
+ "",
+ "26073cc1d851beff176384dc9896d5ff",
+ "0a3ea7a5487cb5f7d70fb6c58d038554"),
+ new GcmTestVector(
+ "001d0c231287c1182784554ca3a21908",
+ "5b9604fe14eadba931b0ccf34843dab9",
+ "921d2507fa8007b7bd067d34",
+ "00112233445566778899aabbccddeeff",
+ "49d8b9783e911913d87094d1f63cc765",
+ "1e348ba07cca2cf04c618cb4"),
+ new GcmTestVector(
+ "2035af313d1346ab00154fea78322105",
+ "aa023d0478dcb2b2312498293d9a9129",
+ "0432bc49ac34412081288127",
+ "aac39231129872a2",
+ "eea945f3d0f98cc0fbab472a0cf24e87",
+ "4bb9b4812519dadf9e1232016d068133"),
+ new GcmTestVector(
+ "2035af313d1346ab00154fea78322105",
+ "aa023d0478dcb2b2312498293d9a9129",
+ "0432bc49ac344120",
+ "aac39231129872a2",
+ "64c36bb3b732034e3a7d04efc5197785",
+ "b7d0dd70b00d65b97cfd080ff4b819d1"),
+ };
+
+ // Conscrypt doesn't support 8-byte nonces
+ private static final GcmTestVector[] OPENSSL_PROVIDER_GCM_TEST_VECTORS = {
+ new GcmTestVector(
+ "001d0c231287c1182784554ca3a21908",
+ "5b9604fe14eadba931b0ccf34843dab9",
+ "028318abc1824029138141a2",
+ "",
+ "26073cc1d851beff176384dc9896d5ff",
+ "0a3ea7a5487cb5f7d70fb6c58d038554"),
+ new GcmTestVector(
+ "001d0c231287c1182784554ca3a21908",
+ "5b9604fe14eadba931b0ccf34843dab9",
+ "921d2507fa8007b7bd067d34",
+ "00112233445566778899aabbccddeeff",
+ "49d8b9783e911913d87094d1f63cc765",
+ "1e348ba07cca2cf0"),
+ new GcmTestVector(
+ "2035af313d1346ab00154fea78322105",
+ "aa023d0478dcb2b2312498293d9a9129",
+ "0432bc49ac34412081288127",
+ "aac39231129872a2",
+ "eea945f3d0f98cc0fbab472a0cf24e87",
+ "4bb9b4812519dadf9e1232016d068133"),
+ };
+
+ // SunJCE doesn't support 8-byte tags
+ private static final GcmTestVector[] SUNJCE_PROVIDER_GCM_TEST_VECTORS = {
+ new GcmTestVector(
+ "001d0c231287c1182784554ca3a21908",
+ "5b9604fe14eadba931b0ccf34843dab9",
+ "028318abc1824029138141a2",
+ "",
+ "26073cc1d851beff176384dc9896d5ff",
+ "0a3ea7a5487cb5f7d70fb6c58d038554"),
+ new GcmTestVector(
+ "2035af313d1346ab00154fea78322105",
+ "aa023d0478dcb2b2312498293d9a9129",
+ "0432bc49ac34412081288127",
+ "aac39231129872a2",
+ "eea945f3d0f98cc0fbab472a0cf24e87",
+ "4bb9b4812519dadf9e1232016d068133"),
+ new GcmTestVector(
+ "2035af313d1346ab00154fea78322105",
+ "aa023d0478dcb2b2312498293d9a9129",
+ "0432bc49ac344120",
+ "aac39231129872a2",
+ "64c36bb3b732034e3a7d04efc5197785",
+ "b7d0dd70b00d65b97cfd080ff4b819d1"),
+ };
+
+ private GcmTestVector[] getTestVectors() {
+ GcmTestVector[] gcmTestVectors = DEFAULT_GCM_TEST_VECTORS;
+ if (Security.getProvider("AndroidOpenSSL") != null) {
+ gcmTestVectors = OPENSSL_PROVIDER_GCM_TEST_VECTORS;
+ } else if (Security.getProvider("SunJCE") != null) {
+ gcmTestVectors = SUNJCE_PROVIDER_GCM_TEST_VECTORS;
+ }
+ return gcmTestVectors;
+ }
+
+ public void testVectors() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ byte[] ct = cipher.doFinal(test.pt);
+ assertEquals(test.ctHex, TestUtil.bytesToHex(ct));
+ }
+ }
+
+ /**
+ * Typically one should always call updateAAD before any call to update. This test checks what
+ * happens if the order is reversed. The test expects that a correct implementation either
+ * computes the tag correctly or throws an exception.
+ *
+ * <p>For example, OpenJdk did compute incorrect tags in this case. The bug has been fixed in
+ * http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/89c06ca1e6cc
+ *
+ * <p>For example BouncyCastle computes correct tags if the calls are reversed, SunJCE and OpenJdk
+ * now throw exceptions.
+ */
+ public void testLateUpdateAAD() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ byte[] c0 = cipher.update(test.pt);
+ try {
+ cipher.updateAAD(test.aad);
+ } catch (java.lang.IllegalStateException ex) {
+ // Throwing an exception is valid behaviour.
+ continue;
+ }
+ byte[] c1 = cipher.doFinal();
+ String result = TestUtil.bytesToHex(c0) + TestUtil.bytesToHex(c1);
+ assertEquals(test.ctHex, result);
+ }
+ }
+
+ /** Encryption with ByteBuffers. */
+ public void testByteBuffer() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ // Encryption
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ int outputSize = cipher.getOutputSize(test.pt.length);
+ ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ptBuffer, ctBuffer);
+ assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
+
+ // Decryption
+ ctBuffer.flip();
+ cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
+ outputSize = cipher.getOutputSize(test.ct.length);
+ ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ctBuffer, decrypted);
+ assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
+ }
+ }
+
+ /** Encryption with ByteBuffers should be copy-safe. */
+ public void testByteBufferAlias() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ // Encryption
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ int outputSize = cipher.getOutputSize(test.pt.length);
+ byte[] backingArray = new byte[outputSize];
+ ByteBuffer ptBuffer = ByteBuffer.wrap(backingArray);
+ ptBuffer.put(test.pt);
+ ptBuffer.flip();
+ ByteBuffer ctBuffer = ByteBuffer.wrap(backingArray);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ptBuffer, ctBuffer);
+ assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
+
+ // Decryption
+ ByteBuffer decrypted = ByteBuffer.wrap(backingArray);
+ ctBuffer.flip();
+ cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ctBuffer, decrypted);
+ assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
+ }
+ }
+
+ public void testReadOnlyByteBuffer() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ // Encryption
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt).asReadOnlyBuffer();
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ int outputSize = cipher.getOutputSize(test.pt.length);
+ ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ptBuffer, ctBuffer);
+ assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
+
+ // Decryption
+ ctBuffer.flip();
+ ctBuffer = ctBuffer.asReadOnlyBuffer();
+ cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
+ outputSize = cipher.getOutputSize(test.ct.length);
+ ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ctBuffer, decrypted);
+ assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
+ }
+ }
+
+ /**
+ * If a ByteBuffer is backed by an array and not readonly, then it is possible to access the data
+ * through the .array() method. An implementation using this possiblity must ensure that it
+ * considers the offset.
+ */
+ public void testByteBufferWithOffset() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ // Encryption
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ ByteBuffer ptBuffer = ByteBuffer.wrap(new byte[test.pt.length + 50]);
+ ptBuffer.position(5);
+ ptBuffer = ptBuffer.slice();
+ ptBuffer.put(test.pt);
+ ptBuffer.flip();
+
+ ByteBuffer ctBuffer = ByteBuffer.wrap(new byte[test.ct.length + 50]);
+ ctBuffer.position(8);
+ ctBuffer = ctBuffer.slice();
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ptBuffer, ctBuffer);
+ assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
+ ctBuffer.flip();
+
+ // Decryption
+ ByteBuffer decBuffer = ByteBuffer.wrap(new byte[test.pt.length + 50]);
+ decBuffer.position(6);
+ decBuffer = decBuffer.slice();
+ cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ cipher.doFinal(ctBuffer, decBuffer);
+ assertEquals(test.ptHex, TestUtil.byteBufferToHex(decBuffer));
+ }
+ }
+
+ public void testByteBufferTooShort() throws Exception {
+ GcmTestVector[] gcmTestVectors = getTestVectors();
+ for (GcmTestVector test : gcmTestVectors) {
+ // Encryption
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
+ ByteBuffer ctBuffer = ByteBuffer.allocate(test.ct.length - 1);
+ cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ try {
+ cipher.doFinal(ptBuffer, ctBuffer);
+ fail("This should not work");
+ } catch (ShortBufferException ex) {
+ // expected
+ }
+
+ // Decryption
+ ctBuffer = ByteBuffer.wrap(test.ct);
+ ByteBuffer decrypted = ByteBuffer.allocate(test.pt.length - 1);
+ cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
+ cipher.updateAAD(test.aad);
+ try {
+ cipher.doFinal(ctBuffer, decrypted);
+ fail("This should not work");
+ } catch (ShortBufferException ex) {
+ // expected
+ }
+ }
+ }
+
+ /**
+ * The default authentication tag size should be 128-bit by default for the following reasons:
+ * <br>
+ * (1) Security: Ferguson, N., Authentication Weaknesses in GCM, Natl. Inst. Stand. Technol. [Web
+ * page], http://www.csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/
+ * CWC-GCM/Ferguson2.pdf, May 20, 2005. This paper points out that a n-bit tag has lower strength
+ * than expected. <br>
+ * (2) Compatibility: Assume an implementer tests some code using one provider than switches to
+ * another provider. Such a switch should ideally not lower the security. <br>
+ * Conscrypt used to have only 12-byte authentication tag (b/26186727).
+ */
+ public void testDefaultTagSizeIvParameterSpec() throws Exception {
+ byte[] counter = new byte[12];
+ byte[] input = new byte[16];
+ byte[] key = new byte[16];
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(counter));
+ } catch (InvalidAlgorithmParameterException ex) {
+ // OpenJDK8 does not support IvParameterSpec for GCM.
+ System.out.println(ex);
+ return;
+ }
+ byte[] output = cipher.doFinal(input);
+ assertEquals(input.length + 16, output.length);
+ }
+
+ /**
+ * The default authentication tag size should be 128-bit by default for the following reasons:
+ * <br>
+ * (1) Security: Ferguson, N., Authentication Weaknesses in GCM, Natl. Inst. Stand. Technol. [Web
+ * page], http://www.csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/
+ * CWC-GCM/Ferguson2.pdf, May 20, 2005. This paper points out that a n-bit tag has lower strength
+ * than expected. <br>
+ * (2) Compatibility: Assume an implementer tests some code using one provider than switches to
+ * another provider. Such a switch should ideally not lower the security. <br>
+ * BouncyCastle used to have only 12-byte authentication tag (b/26186727).
+ */
+ public void testDefaultTagSizeAlgorithmParameterGenerator() throws Exception {
+ byte[] input = new byte[10];
+ byte[] key = new byte[16];
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ try {
+ AlgorithmParameterGenerator.getInstance("GCM");
+ } catch (NoSuchAlgorithmException ex) {
+ // Conscrypt does not support AlgorithmParameterGenerator for GCM.
+ System.out.println(ex);
+ return;
+ }
+ AlgorithmParameters param = AlgorithmParameterGenerator.getInstance("GCM").generateParameters();
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), param);
+ byte[] output = cipher.doFinal(input);
+ assertEquals(input.length + 16, output.length);
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/BasicTest.java b/java/com/google/security/wycheproof/testcases/BasicTest.java
new file mode 100644
index 0000000..1cd9ca4
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/BasicTest.java
@@ -0,0 +1,45 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+
+/** Not a true test: reports information about the provider. */
+public class BasicTest extends TestCase {
+
+ /** List all algorithms known to the security manager. */
+ public void testListAllAlgorithms() {
+ for (Provider p : Security.getProviders()) {
+ System.out.println();
+ System.out.println("Provider:" + p.getName());
+ // Using a TreeSet here, because the elements are sorted.
+ TreeSet<String> list = new TreeSet<String>();
+ for (Object key : p.keySet()) {
+ list.add((String) key);
+ }
+ for (String algorithm : list) {
+ if (algorithm.startsWith("Alg.Alias.")) {
+ continue;
+ }
+ System.out.println(algorithm);
+ }
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/BigIntegerTest.java b/java/com/google/security/wycheproof/testcases/BigIntegerTest.java
new file mode 100644
index 0000000..cd5a992
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/BigIntegerTest.java
@@ -0,0 +1,461 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import junit.framework.TestCase;
+
+/**
+ * Test BigInteger class.
+ *
+ * <p>This unit tests focuses on checking security relevant properties.
+ */
+public class BigIntegerTest extends TestCase {
+ public static final BigInteger[] NONPRIMES =
+ new BigInteger[] {
+ // small non prime integers
+ new BigInteger("-1"),
+ new BigInteger("0"),
+ new BigInteger("1"),
+ // If p is prime then the Mersenne number 2^p-1 is pseudoprime for base 2.
+ new BigInteger("147573952589676412927"),
+ new BigInteger("2361183241434822606847"),
+ // pseudoprime squares derived from Wiefrich primes
+ new BigInteger("1194649"),
+ new BigInteger("12327121"),
+ // G. Jaeschke: "On strong pseudoprimes to several bases", Math o. comp. v.61, p 915-926
+ new BigInteger("2152302898747"),
+ new BigInteger("3474749660383"),
+ new BigInteger("341550071728321"),
+ new BigInteger("41234316135705689041"),
+ new BigInteger("1553360566073143205541002401"),
+ new BigInteger("56897193526942024370326972321"),
+ // A list of strong pseudoprimes to 12 or more bases from
+ // https://arxiv.org/pdf/1509.00864v1.pdf
+ new BigInteger("360681321802296925566181"),
+ new BigInteger("164280218643672633986221"),
+ new BigInteger("318665857834031151167461"),
+ new BigInteger("7395010240794120709381"),
+ new BigInteger("164280218643672633986221"),
+ new BigInteger("318665857834031151167461"),
+ new BigInteger("2995741773170734841812261"),
+ new BigInteger("667636712015520329618581"),
+ new BigInteger("3317044064679887385961981"),
+ new BigInteger("3110269097300703345712981"),
+ new BigInteger("552727880697763694556181"),
+ new BigInteger("360681321802296925566181"),
+ new BigInteger("7395010240794120709381"),
+ new BigInteger("3404730287403079539471001"),
+ new BigInteger("164280218643672633986221"),
+ // Richarg G.E. Pinch, "Some primality testing algorithms"
+ // Some composites that passed Maple V's primality test.
+ new BigInteger("10710604680091"),
+ new BigInteger("4498414682539051"),
+ new BigInteger("6830509209595831"),
+ // Composites that passed the primality test of Mathematica 2.0
+ new BigInteger("38200901201"),
+ new BigInteger("6646915915638769"),
+ // Composites that passed Axioms primality tests
+ new BigInteger("168790877523676911809192454171451"),
+ new BigInteger("68528663395046912244223605902738356719751082784386681071"),
+ // A composite q that was acceptied by Gnu Crypto. p = 2*q + 1 is prime and could have been
+ // used to break the SRP with that library.
+ // http://www.iacr.org/archive/pkc2005/33860010/33860010.pdf
+ new BigInteger(
+ "2338274894573145273314679073561004052325493799717332496500873981"
+ + "9154269566267911565762670147721173495706686483597956042863296855"
+ + "8985491020031718032728786934761830612407539788738389834804112831"
+ + "0484933712924414264511799715503596253054638290097305254378560604"
+ + "3457282155730383806702845548017315217454390994052035233808454053"
+ + "2209678251"),
+ // I. Damgard, P. Landrock, and C. Pomerance. "Average case error estimates for the strong
+ // probable prime test." Math. of Comp. v.61 (203), pp. 177-194.
+ //
+ // This paper gives bounds for the number of bases necessary to distinguish composites from
+ // primes assuming that the tested integer has been chosen at random.
+ //
+ // The result is sometimes misinterpreted and used for pseudo primality tests. There the
+ // assumption of the paper may not be valid, especially if the integer to test has been
+ // chosen by a potentially malicious party. The following pseudoprimes are 1024 to 1280 bits
+ // long, pass the MR test for about 1/4 of all bases. They may expose pseudo primality tests
+ // that misinterpret the paper above.
+ new BigInteger(
+ "1730626114143993906582329178627391355248485443639984363030847275"
+ + "1308542667309368405802823431259718338553667079600118481458180717"
+ + "8685660312964257923307841168376622412972295432300191118906455596"
+ + "0636099366430317210651098229261736987868487865820945209431391380"
+ + "09108180649097618810676094425505547347369635059151651"),
+ new BigInteger(
+ "1360998858923994584770803056737393786894832450662215840614559215"
+ + "7078401469699701619693552331616875038702785662417391573713804038"
+ + "4334162971247398689854706029275431407028615888533012918610480990"
+ + "0223861487963796923928503972465761214360888693859314270808955367"
+ + "40913457414488449790876563256100025424908640036566991"),
+ new BigInteger(
+ "3166883756083864374213797577792765404121225450334428749136082272"
+ + "6277047033553982548405648549530365358167591776542577633638251648"
+ + "4708794514891794859629545011811469601460428778510574606216627610"
+ + "9305946545256861710197652701722202600572822026157108510694466031"
+ + "21873496655525294839125742517721479483987924741221051"),
+ new BigInteger(
+ "1867856940026786421328012256561867196437042470176831233408635728"
+ + "4012048133274069029642553787088950310027377534718962029124718226"
+ + "6051117402306961193255486702389001315623336948708913938663766675"
+ + "8226042898352219886123870222547007370332879734207273564946511954"
+ + "31833673259400609717994958747847898007198993092012403"),
+ new BigInteger(
+ "1796390661263009677994016718416108866609292079197277387452323006"
+ + "0275054640418696223480642324316099214952402651731083265854610369"
+ + "8224730515713772933976457906751697355710699183284927973990745341"
+ + "2311585789546147810071014069499060003398982340466066800822746698"
+ + "64309065127941774208780103317444828873858305613764441"),
+ new BigInteger(
+ "1971945240855615239359385779848543278459852521629467703761094672"
+ + "8118959477624582999696057042356627216821194209090396598966531204"
+ + "6718418693934025583647341695134065566474352554207810854787929284"
+ + "0150420997586371167811999782663434687606795518115913678131471778"
+ + "75984898571603525952885934025286780854976730638309011"),
+ new BigInteger(
+ "3150008132483461686934076250569912489352161839369648385736587811"
+ + "5997183822673267428826594197361084397177321281419482762875475084"
+ + "9549588421903702315436565970387119142993552663715551586581960248"
+ + "0385985798377103010348982470471826679560834315129605222126122792"
+ + "66245495948831504762364224662571600318327270033084451"),
+ new BigInteger(
+ "1708946102366142320715649564941267111465045510329061281476212740"
+ + "3257341007679575909346478379354045686824680545379443269343860874"
+ + "7656833753674500442989626468892341565281803639470271121897646438"
+ + "0297951614184327979794615696929197488480659590917557764806142256"
+ + "64177795195470929762281195447906351417368682849843661"),
+ new BigInteger(
+ "3440003701993474165051634746793659123122285886429390887874425798"
+ + "0539628797086399700050400512078053335053587477375429177907276765"
+ + "7299212000552180980839328379536622696237474649639004862671352175"
+ + "9289352494669383679530748723706821659664185661303953233767365167"
+ + "67872755699135674189217223109386132423577475778316621"),
+ new BigInteger(
+ "1384489093437226718803143517408309162781203263729355872818628349"
+ + "4469526441585078582037579393159945688413133085030944516305313234"
+ + "8118439725196722488178936032989162127096990828542718648126854836"
+ + "3215014994571003679167792328172868632219526006267874696849394364"
+ + "51238457213158274397103569820623680840515654121967511"),
+ new BigInteger(
+ "3164393868232068713466361644489248900506521258778648162638744470"
+ + "1911965299134147189251276735683301303659631352068168884603764242"
+ + "2058303711027020977731971469313828021385806157441077657252831199"
+ + "5151267291454080409585783805054468065763411635886980943812129069"
+ + "12979884469786023782783106107762632814558326808787771"),
+ new BigInteger(
+ "3429610981008641614862240834440649965306153336087134811684334214"
+ + "2781784784880823158748073620472850986640780368357758806487624898"
+ + "6627917970721407574366482474956464008840562218539437088991213443"
+ + "6865812444686702307687466249240837612849694711488568460832793683"
+ + "75653516879275492605255161494494045951397742913942521"),
+ new BigInteger(
+ "1452625971469501984029833170297844688666257429198467445330023676"
+ + "9656278238192507513913993052034672663086092503841752084104847874"
+ + "8173408690100803386628315407260460724324957380860416531476612359"
+ + "3906755149555321240901275978836270398698785709389076413509994529"
+ + "42901485886289548101644664410043634050840333618736241"),
+ new BigInteger(
+ "1038759703926769528247935492263828939187707228977771863002037516"
+ + "6447956205097712397228992931571755867770661683705025240420111189"
+ + "2868394359927108413461144788316226799790655169187714036057483534"
+ + "1379449940364129845302840193911613461736295410032863048528135257"
+ + "04436628490382188950208123780350213139500089456366841"),
+ new BigInteger(
+ "2092626848347087607813788288260128832160456227715887480495928337"
+ + "8143090879636401536763351823849725734769339835456348322174433133"
+ + "2528919261931329808331753456631473557050588173643619875493912344"
+ + "2621229276297788264420214803881217267094948976676445054939538411"
+ + "22580436721054077839958796624587867034849970594728503"),
+ new BigInteger(
+ "2599619740922490310102276030628575944314398371981276430688469612"
+ + "6677200542107317525516057185980658562393307608335402672015071146"
+ + "4375869967746325500371685760342898099183114419807958654613613854"
+ + "3992594086574371567802232690430810966098771990068625112489903295"
+ + "89067604336669355585402887916288037943709029191674911"),
+ new BigInteger(
+ "1484944124031033226177904474729672080414277081288126930486713099"
+ + "2951571588154552341076434413035940622712601649739964234772603407"
+ + "4857469854866669198948655053082186111410005989963123962723450119"
+ + "6642285521712848015932226566546835102733706632115364632204156914"
+ + "64644614536183219912321808854090915103775109695786903"),
+ new BigInteger(
+ "1989518237873611249304118136102198299910749751063921465712157675"
+ + "0160983808717982713586255483659294934004326549705203383719900307"
+ + "1263871954417468537542759843054899935687365194283002403584007149"
+ + "4878371117610681917576307737065411378178051858121032451282900716"
+ + "73542006653340382017735899123084476453857081318545991"),
+ new BigInteger(
+ "1001516549472529960430483041632117547467775871427023066924341669"
+ + "8403875533009883195522874469432253701609651260735835128759135299"
+ + "5655554893223580483857764100115214746205606713424344869011314868"
+ + "3107942731565140938612794494135227597999675233998980692687287393"
+ + "67463341929936509718884001903262839905032784262429503"),
+ new BigInteger(
+ "9523120659259647017050060990584944204556454726505878376759616021"
+ + "0162649328723702952067039028722189901551617226203049071432575686"
+ + "9121080710327716161595367835528315683397536615084723082551568364"
+ + "5739952184995573677453019127607472426963971562388390300785220049"
+ + "6655144350028488056721467755918814393298596327869403"),
+ new BigInteger(
+ "1132692896131390459872218381686704761578367301590229517271338668"
+ + "7180351798454882497438382954425835621126393661367213143371283272"
+ + "0317909560575328664237540188143415517690966913820407105917871661"
+ + "6365405171372246705778112163771743546945868623307467307997875571"
+ + "40869529264839386342569691698111927128704157615097153"),
+ new BigInteger(
+ "1468478445343635885853097900396288249751127795088868633754583040"
+ + "9902362001013473990040942210829761549194134324343879441927807081"
+ + "4832779046634885071582835688508933384516245429006116427382617949"
+ + "0797131644177507421862332328509904031871287120929769029086074503"
+ + "38866991708762791875618755240139448209180903665732503"),
+ new BigInteger(
+ "3584128102219288461651881096063603237206550481422480899564693370"
+ + "6989198816192527918220789937223699304075118319904981106473056074"
+ + "6022073963857677172123650694187762839204698560127083582857191356"
+ + "7619601857134928125369766912580367127840531257344393938629885107"
+ + "16841734490107828355376447675347185589367615046902903"),
+ new BigInteger(
+ "1364132540730201251194341844655148002850736352953819312409033451"
+ + "0581806956034928961765696532883678319811153534823893271895441595"
+ + "1560405730847235775035340408484490592989244418679611824558459897"
+ + "3970103405588145228028549820125837425523682281669049087481368021"
+ + "33702260393866732616878693744975284760231993354960641"),
+ new BigInteger(
+ "1201213090774136737579735845388953400530787071160074364126728551"
+ + "5147303301856817241515212573079940841340044269783294804816431383"
+ + "8284868252529547559069691488487393115675459439240223181642866729"
+ + "3429931964973711015111163544551414299071832349845971998375812575"
+ + "43510797169400923829329952407436122292964382266031253"),
+ new BigInteger(
+ "2749611624987217008377958765718501619519235049877079452181305657"
+ + "4724564026272242180811435338643866876903591496649439319889570905"
+ + "0358277453956447636555409300854018401232502616530331143658908539"
+ + "1682266093367017969369633046927346949982338985082398103545735993"
+ + "26268702707614772584950389057955691219494031838859791"),
+ new BigInteger(
+ "2472982114742145360236684931488791833991329788857529670921519821"
+ + "2275589064185672494327017904494686810840150314271250166999768972"
+ + "5488277075239138647902134463451436706674384070937644414378922408"
+ + "3974240802538174272534726968041801996779685771019246098603577098"
+ + "48139330190576017582503777009836399771498662905893541"),
+ new BigInteger(
+ "1865347188865809981733701115448160790425846704558108501171803277"
+ + "4616363375301457541345495992357828826645510919897778446537615423"
+ + "0882378024111971510810465276396395657415178370245114122816237302"
+ + "3283933030997110906700611097744954222271394790237582780817507949"
+ + "50528224900273599212004329531461848157373189908642761"),
+ new BigInteger(
+ "2852220663043188088074403487569592065121097371561337653207919689"
+ + "5806125544163953214258963319594971029379263400735515369955250013"
+ + "4028759770788754166339078427645792536001991144766729628117371050"
+ + "3065276544543379585207323093069812639902415298676791716773723086"
+ + "01834079961869281917489638496882679996929360595283091"),
+ new BigInteger(
+ "1812266945737014247808099956042081894034544124660090203840602123"
+ + "8933795306490611245152382127750687774085253618514158494675518742"
+ + "0904863344271961110077635791220319963938065397633608138595169161"
+ + "4365952732191284608496816156732317034130054052863296504407952482"
+ + "70402413500178325587999299003705988651612697260381081"),
+ new BigInteger(
+ "3461478020849089881636057301867459968070516872602987322072552610"
+ + "6122696717667098851127207650635960731479969936151065921604956606"
+ + "9966154794154897232197433347544538725616640069913605417680979153"
+ + "7941663920296351630552463916932109774095427601318332413237900565"
+ + "33380330505490643091283956267491266793755039018149751"),
+ new BigInteger(
+ "2919979800970068658905539811038971051531482233418344434620488229"
+ + "7069955478191515351496193695554391114007400265274653645749899336"
+ + "1682279972987736655018586409178146143048864596533190807270958265"
+ + "8386345811616055097769189859096393752934393213978617302764485594"
+ + "27971296399182413971389773786687947710326691137231821"),
+ new BigInteger(
+ "4145154657949019520090421067892641813006171355169512965016842717"
+ + "9656056083456770700476740539321891137934371895885040718614132068"
+ + "7659642286859932894319946334724710913927915623235424403674960713"
+ + "3015105499354740364264523832014989327244648027567866644179973588"
+ + "6851400410006028767095438327490143741004842299878541824964849824"
+ + "9350463409537126165182086675091928210325509674933575383432172361"
+ + "1"),
+ new BigInteger(
+ "7263570684005586918409651676342477962666063384721447164820162267"
+ + "3637900031379949446961412145104626127789865770334124795558653625"
+ + "0265693033953361779942717984970881106667840356057452866357943677"
+ + "0299187611159071848712668510417692823114550446719084221850233353"
+ + "5448622581084864206413295247972240845959033925761759264503271102"
+ + "8711358281311325650083539770515252900036932499310037595977096965"
+ + "3"),
+ new BigInteger(
+ "3266663369261434628530741133725226939380890029427130078147736465"
+ + "2996576096098663002890375510448427552966457154556853852292297530"
+ + "3748877081504218804805934729044054195328441392083622877088337833"
+ + "3839361634881282676119589334709165541036798092721269225600972531"
+ + "5718770210834831734568895865334347621480511738343920340920819445"
+ + "8602267925535790135884214787193459118783550610652631217006506945"
+ + "3"),
+ new BigInteger(
+ "2714275054823322283846947242758076394288969833351667671546539844"
+ + "8651643040817257191932781992745878593029648459331742640462067216"
+ + "1697889841582474665251728415469605782526629276939159099241968231"
+ + "4563946417035619325266947257091436696492494177352417584114484475"
+ + "6610785746958696759938071286674788996869751533043564234638049802"
+ + "5949514917474176492949501669603402532532836245346872590582496734"
+ + "1"),
+ new BigInteger(
+ "9266983839147571189339684823228253420616685503762301572754412275"
+ + "1127843293258964600702452397526178329259267484695086911638972315"
+ + "4961995491900251718105624646921122900256992784437600453557273835"
+ + "3861591882136393291951512396743267427648075154617935904316277726"
+ + "4493865072538820667287351636308197262473273185496543102226470825"
+ + "6662877019047683511136380480413028925833068997034750517865449915"
+ + "3"),
+ new BigInteger(
+ "6943685859962113005380005918916483733270787990846044283782171250"
+ + "1096851232736318325302320935157976786131666696364333532268184395"
+ + "8665950723719162662956110077840013184726020313880442980629145593"
+ + "2383952066228056762115442513166346145910224582828425403465971492"
+ + "7260150227126350939033438077449255619231502836209591891037493966"
+ + "9366963730251619187615962926310287121840421140621429191345783703"
+ + "1"),
+ new BigInteger(
+ "8697498751458522624235585703214358189002281420472600166267178848"
+ + "9809876665869248037334395420081653868096056103537493131465377226"
+ + "0261527380426559408040456405219848362023445401145511114936506394"
+ + "6240472545398288332411818055040869427951279027405975059749360297"
+ + "5868667379863439430711990295232153128900808256212596912819669440"
+ + "8461633147852596585348243485566178333170181585431955731179108942"
+ + "1"),
+ new BigInteger(
+ "4252141813347264797276096871298065242070358505647997888003056375"
+ + "0053145248543520793105289129514510723624029989029530989695904117"
+ + "1040883775014117200916554841688641022136017868157290925811239787"
+ + "3664014299809018676076741787758620956387796785085878200748397774"
+ + "1000982778291877557074489243525397961477916369196578483491169386"
+ + "2005017885694815977695115290403992818456642027646266206320076800"
+ + "3"),
+ new BigInteger(
+ "3356647398302910967427184201762737607743709740247537918189248572"
+ + "1755339542838026890625250818518527348898974773340867800840791470"
+ + "3182072707032492007084043715576322632015800128489921814932124611"
+ + "2300036417841991332124497348096579076242448857352000771247540736"
+ + "1254949324799638105796121388483225300620211599611028678202393567"
+ + "8095635541751658983704832859578366318530922805928053806070359946"
+ + "1"),
+ new BigInteger(
+ "3687125575229624930459923973437509789116885700012081850445193578"
+ + "4486423768425089350932846437401841871613673810991112360643320652"
+ + "0225782089986669258803208183278659152741552450801685341843048568"
+ + "1125008729650000322084879372381541270180139663134377177885154388"
+ + "9558281508372272794193460069397070875763691455289959733530070186"
+ + "0360525342531389354962332229432027179470095997955180502375530175"
+ + "3"),
+ new BigInteger(
+ "6088560764944279853795552546797623009536823218028533977947580608"
+ + "2015023514992395624319060987001625566234648211868300524182306472"
+ + "7026872385780533326083682960047644674758988927136149502626557718"
+ + "2561494515318563339483672950711193945073071458843901227339418284"
+ + "3084182493461642555372639047162641075337152622892862251731700231"
+ + "6672547426448574167370804559242233207791080547486632014153528258"
+ + "1"),
+ new BigInteger(
+ "6081766267938901970682791123502557184373300073506187731779846380"
+ + "4083193288475152882563422230130613717216469536080649276981712202"
+ + "8895707724700107471391574673087393411637415445150131834443587280"
+ + "4243131225731630921851260690656608624225797294197741881140769183"
+ + "0474230365914155543155728342161658185646742117306992051014301383"
+ + "8040790841165308968256142923362988225719340573836171022480960175"
+ + "3"),
+ new BigInteger(
+ "5000879164859908887599881582814678322611278734193303790540199067"
+ + "6946804876309491380295619810590406766227048051997595053442615914"
+ + "2677702465219525342790323338314172797422380779526016709102650201"
+ + "6058553529785304239405043134061167377896985489252957729348463979"
+ + "6066933483020351454994081895283883114206539208013308687170796286"
+ + "8268752695525736731805658439398227370325903928664994918343915975"
+ + "3"),
+ new BigInteger(
+ "5033660524073962747735388920230339629907033897027296197974576730"
+ + "5654422857706257645566447425553553516325935964234373316093019314"
+ + "9125347663842235853602126989737378697014753612431648011618832921"
+ + "3881347704723060451053853932258315572365588301231482715348124261"
+ + "9244292433503547002496906691530720882968955274299548904791181715"
+ + "4190217453383503386985567684902027707247767653326442247588135031"
+ + "1"),
+ new BigInteger(
+ "7656692474335471169217545128846872228367812415627865759181393395"
+ + "8241618825828371173259648247363305034462523584509943049089351382"
+ + "5433879053475325827330864407124355159557574919864955631956757119"
+ + "9044097578241324151657090338112756973390540016908863938814598847"
+ + "5396824620980380695503598397306050849284639259137342875066075738"
+ + "4060141031090753207116787791385102134328808638802350088507846845"
+ + "1"),
+ new BigInteger(
+ "6916552449605114038869281931877716049700938960849845402874660241"
+ + "3416574115770967736955518993475194932835724065347138687353620520"
+ + "8331524408574865319265572656228099650675609929009824224767253657"
+ + "5459382651810818256784829505942965567114371502731619372511210627"
+ + "1610362520274480185346478545007812850057950851029848830710521787"
+ + "8356932374617076535457900683468313279449103472700012568700849319"
+ + "1"),
+ // F. Arnault, "Rabin-Miller primality test: composite numbers which pass it", Math. comp.
+ // v.64, n.209, p 355-361.
+ //
+ // A strong pseudoprime for the first 46 primes
+ new BigInteger(
+ "8038374574536394912570796143419421081388376882875581458374889175"
+ + "2229742737653336521865023361639600454579150420236032087665699667"
+ + "6098728404396540823292873879185086916685732826776177102938969773"
+ + "9470167082304286871099974399765441448453411558724506334092790222"
+ + "7529622941498423068816854043264575340183297861112989606448452161"
+ + "91652872597534901"),
+ // Richard G.E. Pinch, Absolute quadratic pseudorprimes
+ // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.210.6783&rep=rep1&type=pdf
+ // Lucas-Charmichael-(-) numbers
+ new BigInteger("28295303263921"),
+ new BigInteger("443372888629441"),
+ new BigInteger("582920080863121"),
+ new BigInteger("894221105778001"),
+ new BigInteger("2013745337604001"),
+ // Lucas-Charmichael-(+) numbers
+ new BigInteger("6479"),
+ new BigInteger("84419"),
+ new BigInteger("1930499"),
+ new BigInteger("7110179"),
+ new BigInteger("15857855"),
+ new BigInteger("63278892599"),
+ new BigInteger("79397009999"),
+ };
+
+ /**
+ * Tests BigInteger.isProbablePrime with a list of composite integers. The integers have been
+ * chosen to check for weak pseudoprimality tests. E.g., they are counterexamples to weak
+ * implementations. The implementation in jdk uses a combination of a Miller-Rabin test and a
+ * Lucas test. This is similar to the Baillie-PSW test
+ * https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
+ */
+ public void testIsProbablePrime() throws Exception {
+ // The probability that a non-prime passes should be at most 1-2^{-certainty}.
+ int certainty = 80;
+ for (BigInteger n : NONPRIMES) {
+ if (n.isProbablePrime(certainty)) {
+ fail("Composite number " + n.toString() + " passed as probable prime test");
+ }
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java b/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java
new file mode 100644
index 0000000..f094a3b
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/CipherInputStreamTest.java
@@ -0,0 +1,279 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import junit.framework.TestCase;
+
+/** CipherInputStream tests */
+public class CipherInputStreamTest extends TestCase {
+ static final SecureRandom rand = new SecureRandom();
+
+ static byte[] randomBytes(int size) {
+ byte[] bytes = new byte[size];
+ rand.nextBytes(bytes);
+ return bytes;
+ }
+
+ static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
+ return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ }
+
+ static AlgorithmParameterSpec randomParameters(
+ String algorithm, int ivSizeInBytes, int tagSizeInBytes) {
+ if ("AES/GCM/NoPadding".equals(algorithm) || "AES/EAX/NoPadding".equals(algorithm)) {
+ return new GCMParameterSpec(8 * tagSizeInBytes, randomBytes(ivSizeInBytes));
+ }
+ return null;
+ }
+
+ /** Test vectors */
+ public static class TestVector {
+ public String algorithm;
+ public SecretKeySpec key;
+ public AlgorithmParameterSpec params;
+ public byte[] pt;
+ public byte[] aad;
+ public byte[] ct;
+
+ @SuppressWarnings("InsecureCipherMode")
+ public TestVector(
+ String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
+ throws Exception {
+ this.algorithm = algorithm;
+ this.key = randomKey(algorithm, keySize);
+ this.params = randomParameters(algorithm, ivSize, tagSize);
+ this.pt = randomBytes(ptSize);
+ this.aad = randomBytes(aadSize);
+ Cipher cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
+ cipher.updateAAD(aad);
+ this.ct = cipher.doFinal(pt);
+ }
+ }
+
+ Iterable<TestVector> getTestVectors(
+ String algorithm,
+ int[] keySizes,
+ int[] ivSizes,
+ int[] tagSizes,
+ int[] ptSizes,
+ int[] aadSizes)
+ throws Exception {
+ ArrayList<TestVector> result = new ArrayList<TestVector>();
+ for (int keySize : keySizes) {
+ for (int ivSize : ivSizes) {
+ for (int tagSize : tagSizes) {
+ for (int ptSize : ptSizes) {
+ for (int aadSize : aadSizes) {
+ result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testEncrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ InputStream is = new ByteArrayInputStream(t.pt);
+ CipherInputStream cis = new CipherInputStream(is, cipher);
+ byte[] result = new byte[t.ct.length];
+ int totalLength = 0;
+ int length = 0;
+ do {
+ length = cis.read(result, totalLength, result.length - totalLength);
+ if (length > 0) {
+ totalLength += length;
+ }
+ } while (length >= 0 && totalLength != result.length);
+ assertEquals(-1, cis.read());
+ assertEquals(TestUtil.bytesToHex(t.ct), TestUtil.bytesToHex(result));
+ cis.close();
+ }
+ }
+
+ /** JDK-8016249: CipherInputStream in decrypt mode fails on close with AEAD ciphers */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testDecrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ InputStream is = new ByteArrayInputStream(t.ct);
+ CipherInputStream cis = new CipherInputStream(is, cipher);
+ byte[] result = new byte[t.pt.length];
+ int totalLength = 0;
+ int length = 0;
+ do {
+ length = cis.read(result, totalLength, result.length - totalLength);
+ if (length > 0) {
+ totalLength += length;
+ }
+ } while (length >= 0 && totalLength != result.length);
+ assertEquals(-1, cis.read());
+ cis.close();
+ assertEquals(TestUtil.bytesToHex(t.pt), TestUtil.bytesToHex(result));
+ }
+ }
+
+ /**
+ * JDK-8016171 : CipherInputStream masks ciphertext tampering with AEAD ciphers in decrypt mode
+ * Further description of the bug is here:
+ * https://blog.heckel.xyz/2014/03/01/cipherinputstream-for-aead-modes-is-broken-in-jdk7-gcm/
+ * BouncyCastle claims that this bug is fixed in version 1.51. However, the test below still fails
+ * with BouncyCastle v 1.52. A possible explanation is that BouncyCastle has its own
+ * implemenatation of CipherInputStream (org.bouncycastle.crypto.io.CipherInputStream).
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testCorruptDecrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
+ ct[ct.length - 1] ^= (byte) 1;
+ InputStream is = new ByteArrayInputStream(ct);
+ CipherInputStream cis = new CipherInputStream(is, cipher);
+ try {
+ byte[] result = new byte[t.pt.length];
+ int totalLength = 0;
+ int length = 0;
+ do {
+ length = cis.read(result, totalLength, result.length - totalLength);
+ if (length > 0) {
+ totalLength += length;
+ }
+ } while (length >= 0 && totalLength != result.length);
+ cis.close();
+ if (result.length > 0) {
+ fail(
+ "this should fail; decrypted:"
+ + TestUtil.bytesToHex(result)
+ + " pt: "
+ + TestUtil.bytesToHex(t.pt));
+ }
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testCorruptDecryptEmpty(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
+ ct[ct.length - 1] ^= (byte) 1;
+ InputStream is = new ByteArrayInputStream(ct);
+ CipherInputStream cis = new CipherInputStream(is, cipher);
+ try {
+ byte[] result = new byte[t.pt.length];
+ int totalLength = 0;
+ int length = 0;
+ do {
+ length = cis.read(result, totalLength, result.length - totalLength);
+ if (length > 0) {
+ totalLength += length;
+ }
+ } while (length >= 0 && totalLength != result.length);
+ cis.close();
+ fail("this should fail");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+ }
+
+ public void testAesGcm() throws Exception {
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {0, 8, 16, 65, 8100};
+ final int[] aadSizes = {0, 8, 24};
+ Iterable<TestVector> v =
+ getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testEncrypt(v);
+ testDecrypt(v);
+ }
+
+ public void testCorruptAesGcm() throws Exception {
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {8, 16, 65, 8100};
+ final int[] aadSizes = {0, 8, 24};
+ Iterable<TestVector> v =
+ getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testCorruptDecrypt(v);
+ }
+
+ /**
+ * Unfortunately Oracle thinks that returning an empty array is valid behaviour for corrupt
+ * ciphertexts. Because of this we test empty plaintext separately to distinguish behaviour
+ * considered acceptable by Oracle from other behaviour.
+ */
+ public void testEmptyPlaintext() throws Exception {
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {0};
+ final int[] aadSizes = {0, 8, 24};
+ Iterable<TestVector> v =
+ getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testCorruptDecryptEmpty(v);
+ }
+
+ /** Tests CipherOutputStream with AES-EAX if this algorithm is supported by the provider. */
+ public void testAesEax() throws Exception {
+ final String algorithm = "AES/EAX/NoPadding";
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12, 16};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {0, 8, 16, 65, 8100};
+ final int[] aadSizes = {0, 8, 24};
+ try {
+ Cipher.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("Skipping testAesEax");
+ return;
+ }
+ Iterable<TestVector> v =
+ getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testEncrypt(v);
+ testDecrypt(v);
+ testCorruptDecrypt(v);
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java b/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java
new file mode 100644
index 0000000..735056e
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/CipherOutputStreamTest.java
@@ -0,0 +1,239 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import junit.framework.TestCase;
+
+/** CipherOutputStream tests */
+public class CipherOutputStreamTest extends TestCase {
+ static final SecureRandom rand = new SecureRandom();
+
+ static byte[] randomBytes(int size) {
+ byte[] bytes = new byte[size];
+ rand.nextBytes(bytes);
+ return bytes;
+ }
+
+ static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
+ return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
+ }
+
+ static AlgorithmParameterSpec randomParameters(
+ String algorithm, int ivSizeInBytes, int tagSizeInBytes) {
+ if ("AES/GCM/NoPadding".equals(algorithm) || "AES/EAX/NoPadding".equals(algorithm)) {
+ return new GCMParameterSpec(8 * tagSizeInBytes, randomBytes(ivSizeInBytes));
+ }
+ return null;
+ }
+
+ /** Test vectors */
+ @SuppressWarnings("InsecureCipherMode")
+ public static class TestVector {
+ public String algorithm;
+ public SecretKeySpec key;
+ public AlgorithmParameterSpec params;
+ public byte[] pt;
+ public byte[] aad;
+ public byte[] ct;
+
+ public TestVector(
+ String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
+ throws Exception {
+ this.algorithm = algorithm;
+ this.key = randomKey(algorithm, keySize);
+ this.params = randomParameters(algorithm, ivSize, tagSize);
+ this.pt = randomBytes(ptSize);
+ this.aad = randomBytes(aadSize);
+ Cipher cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
+ cipher.updateAAD(aad);
+ this.ct = cipher.doFinal(pt);
+ }
+ }
+
+ Iterable<TestVector> getTestVectors(
+ String algorithm,
+ int[] keySizes,
+ int[] ivSizes,
+ int[] tagSizes,
+ int[] ptSizes,
+ int[] aadSizes)
+ throws Exception {
+ ArrayList<TestVector> result = new ArrayList<TestVector>();
+ for (int keySize : keySizes) {
+ for (int ivSize : ivSizes) {
+ for (int tagSize : tagSizes) {
+ for (int ptSize : ptSizes) {
+ for (int aadSize : aadSizes) {
+ result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testEncrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ CipherOutputStream cos = new CipherOutputStream(os, cipher);
+ cos.write(t.pt);
+ cos.close();
+ assertEquals(TestUtil.bytesToHex(t.ct), TestUtil.bytesToHex(os.toByteArray()));
+ }
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testDecrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ CipherOutputStream cos = new CipherOutputStream(os, cipher);
+ cos.write(t.ct);
+ cos.close();
+ assertEquals(TestUtil.bytesToHex(t.pt), TestUtil.bytesToHex(os.toByteArray()));
+ }
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testCorruptDecrypt(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
+ ct[ct.length - 1] ^= (byte) 1;
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ CipherOutputStream cos = new CipherOutputStream(os, cipher);
+ cos.write(ct);
+ try {
+ // cos.close() should call cipher.doFinal().
+ cos.close();
+ byte[] decrypted = os.toByteArray();
+ // Unfortunately Oracle thinks that returning an empty array is valid behaviour.
+ // We accept empty results here, but flag them in the next test, so that we can distinguish
+ // between beheviour considered acceptable by Oracle and more serious flaws.
+ if (decrypted.length > 0) {
+ fail(
+ "this should fail; decrypted:"
+ + TestUtil.bytesToHex(decrypted)
+ + " pt: "
+ + TestUtil.bytesToHex(t.pt));
+ }
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testCorruptDecryptEmpty(Iterable<TestVector> tests) throws Exception {
+ for (TestVector t : tests) {
+ Cipher cipher = Cipher.getInstance(t.algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
+ cipher.updateAAD(t.aad);
+ byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
+ ct[ct.length - 1] ^= (byte) 1;
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ CipherOutputStream cos = new CipherOutputStream(os, cipher);
+ cos.write(ct);
+ try {
+ // cos.close() should call cipher.doFinal().
+ cos.close();
+ byte[] decrypted = os.toByteArray();
+ fail(
+ "this should fail; decrypted:"
+ + TestUtil.bytesToHex(decrypted)
+ + " pt: "
+ + TestUtil.bytesToHex(t.pt));
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+ }
+
+ public void testAesGcm() throws Exception {
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {8, 16, 65, 8100};
+ final int[] aadSizes = {0, 8, 24};
+ Iterable<TestVector> v =
+ getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testEncrypt(v);
+ testDecrypt(v);
+ testCorruptDecrypt(v);
+ }
+
+ /**
+ * Unfortunately Oracle thinks that returning an empty array is valid behaviour for corrupt
+ * ciphertexts. Because of this we test empty plaintext separately to distinguish behaviour
+ * considered acceptable by Oracle from other behaviour.
+ */
+ public void testEmptyPlaintext() throws Exception {
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {0};
+ final int[] aadSizes = {0, 8, 24};
+ Iterable<TestVector> v =
+ getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testEncrypt(v);
+ testDecrypt(v);
+ testCorruptDecryptEmpty(v);
+ }
+
+ /** Tests CipherOutputStream with AES-EAX if AES-EAS is supported by the provider. */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testAesEax() throws Exception {
+ final String algorithm = "AES/EAX/NoPadding";
+ final int[] keySizes = {16, 32};
+ final int[] ivSizes = {12, 16};
+ final int[] tagSizes = {12, 16};
+ final int[] ptSizes = {8, 16, 65, 8100};
+ final int[] aadSizes = {0, 8, 24};
+ try {
+ Cipher.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("Skipping testAesEax");
+ return;
+ }
+ Iterable<TestVector> v =
+ getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
+ testEncrypt(v);
+ testDecrypt(v);
+ testCorruptDecrypt(v);
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/DhTest.java b/java/com/google/security/wycheproof/testcases/DhTest.java
new file mode 100644
index 0000000..3e9c9e7
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/DhTest.java
@@ -0,0 +1,396 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import com.google.security.wycheproof.WycheproofRunner.SlowTest;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import javax.crypto.KeyAgreement;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import junit.framework.TestCase;
+
+/**
+ * Testing Diffie-Hellman key agreement.
+ *
+ * <p>Subgroup confinment attacks:
+ * The papers by van Oorshot and Wiener rsp. Lim and Lee show that Diffie-Hellman keys can
+ * be found much faster if the short exponents are used and if the multiplicative group modulo p
+ * contains small subgroups. In particular an attacker can try to send a public key that is an
+ * element of a small subgroup. If the receiver does not check for such elements then may be
+ * possible to find the private key modulo the order of the small subgroup.
+ * Several countermeasures against such attacks have been proposed: For example IKE uses
+ * fields of order p where p is a safe prime (i.e. q=(p-1)/2), hence the only elements of small
+ * order are 1 and p-1.
+ * NIST SP 800-56A rev. 2, Section 5.5.1.1 only requires that the size of the subgroup generated
+ * by the generator g is big enough to prevent the baby-step giant-step algorithm. I.e. for 80-bit
+ * security p must be at least 1024 bits long and the prime q must be at least 160 bits long. A 2048
+ * bit prime p and a 224 bit prime q are sufficient for 112 bit security. To avoid subgroup
+ * confinment attacks NIST requires that public keys are validated, i.e. by checking that a public
+ * key y satisfies the conditions 2 <= y <= p-2 and y^q mod p == 1 (Section 5.6.2.3.1). Further,
+ * after generating the shared secret z = y_a ^ x_b mod p each party should check that z != 1. RFC
+ * 2785 contains similar recommendations.
+ * The public key validation described by NIST requires that the order q of the generator g
+ * is known to the verifier. Unfortunately, the order q is missing in PKCS #3. PKCS #3 describes
+ * the Diffie-Hellman parameters only by the values p, g and optionally the key size in bits.
+ *
+ * <p>The class DHParameterSpec that defines the Diffie-Hellman parameters in JCE contains the same
+ * values as PKCS#3. In particular, it does not contain the order of the subgroup q.
+ * Moreover, the SUN provider uses the minimal sizes specified by NIST for q.
+ * Essentially the provider reuses the parameters for DSA.
+ *
+ * <p>Therefore, there is no guarantee that an implementation of Diffie-Hellman is secure against
+ * subgroup confinement attacks. Without a key validation it is insecure to use the key-pair
+ * generation from NIST SP 800-56A Section 5.6.1.1 (The key-pair generation there only requires that
+ * static and ephemeral private keys are randomly chosen in the range 1..q-1).
+ *
+ * <p>To avoid big disasters the tests below require that key sizes are not minimal. I.e., currently
+ * the tests require at least 512 bit keys for 1024 bit fields. We use this lower limit because that
+ * is what the SUN provider is currently doing. TODO(bleichen): Find a reference supporting or
+ * disproving that decision.
+ *
+ * <p>References: P. C. van Oorschot, M. J. Wiener, "On Diffie-Hellman key agreement with short
+ * exponents", Eurocrypt 96, pp 332–343.
+ *
+ * <p>C.H. Lim and P.J. Lee, "A key recovery attack on discrete log-based schemes using a prime
+ * order subgroup", CRYPTO' 98, pp 249–263.
+ *
+ * <p>NIST SP 800-56A, revision 2, May 2013
+ * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
+ *
+ * <p>PKCS #3, Diffie–Hellman Key Agreement
+ * http://uk.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm
+ *
+ * <p>RFC 2785, "Methods for Avoiding 'Small-Subgroup' Attacks on the Diffie-Hellman Key Agreement
+ * Method for S/MIME", March 2000
+ * https://www.ietf.org/rfc/rfc2785.txt
+ *
+ * <p>D. Adrian et al. "Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice"
+ * https://weakdh.org/imperfect-forward-secrecy-ccs15.pdf
+ * A good analysis of various DH implementations.
+ * Some misconfigurations pointed out in the paper are: p is composite, p-1 contains no large
+ * prime factor, q is used instead of the generator g.
+ *
+ * <p>Sources that might be used for additional tests:
+ *
+ * CVE-2015-3193: The Montgomery squaring implementation in crypto/bn/asm/x86_64-mont5.pl
+ * in OpenSSL 1.0.2 before 1.0.2e on the x86_64 platform, as used by the BN_mod_exp function,
+ * mishandles carry propagation
+ * https://blog.fuzzing-project.org/31-Fuzzing-Math-miscalculations-in-OpenSSLs-BN_mod_exp-CVE-2015-3193.html
+ *
+ * <p>CVE-2016-0739: libssh before 0.7.3 improperly truncates ephemeral secrets generated for the
+ * (1) diffie-hellman-group1 and (2) diffie-hellman-group14 key exchange methods to 128 bits ...
+ *
+ * <p>CVE-2015-1787 The ssl3_get_client_key_exchange function in s3_srvr.c in OpenSSL 1.0.2 before
+ * 1.0.2a, when client authentication and an ephemeral Diffie-Hellman ciphersuite are enabled,
+ * allows remote attackers to cause a denial of service (daemon crash) via a ClientKeyExchange
+ * message with a length of zero.
+ *
+ * <p>CVE-2015-0205 The ssl3_get_cert_verify function in s3_srvr.c in OpenSSL 1.0.0 before 1.0.0p
+ * and 1.0.1 before 1.0.1k accepts client authentication with a Diffie-Hellman (DH) certificate
+ * without requiring a CertificateVerify message, which allows remote attackers to obtain access
+ * without knowledge of a private key via crafted TLS Handshake Protocol traffic to a server that
+ * recognizes a Certification Authority with DH support.
+ *
+ * <p>CVE-2016-0701 The DH_check_pub_key function in crypto/dh/dh_check.c in OpenSSL 1.0.2 before
+ * 1.0.2f does not ensure that prime numbers are appropriate for Diffie-Hellman (DH) key exchange,
+ * which makes it easier for remote attackers to discover a private DH exponent by making multiple
+ * handshakes with a peer that chose an inappropriate number, as demonstrated by a number in an
+ * X9.42 file.
+ *
+ * <p>CVE-2006-1115 nCipher HSM before 2.22.6, when generating a Diffie-Hellman public/private key
+ * pair without any specified DiscreteLogGroup parameters, chooses random parameters that could
+ * allow an attacker to crack the private key in significantly less time than a brute force attack.
+ *
+ * <p>CVE-2015-1716 Schannel in Microsoft Windows Server 2003 SP2, Windows Vista SP2, Windows Server
+ * 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and
+ * Windows RT Gold and 8.1 does not properly restrict Diffie-Hellman Ephemeral (DHE) key lengths,
+ * which makes it easier for remote attackers to defeat cryptographic protection mechanisms via
+ * unspecified vectors, aka "Schannel Information Disclosure Vulnerability.
+ *
+ * <p>CVE-2015-2419: Random generation of the prime p allows Pohlig-Hellman and probably other
+ * stuff.
+ *
+ * <p> J. Fried et al. "A kilobit hidden SNFS discrete logarithm computation".
+ * http://eprint.iacr.org/2016/961.pdf
+ * Some crypto libraries use fields that can be broken with the SNFS.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+public class DhTest extends TestCase {
+ public DHParameterSpec ike1536() {
+ final BigInteger p =
+ new BigInteger(
+ "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+ + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+ + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+ + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+ + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+ + "9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff",
+ 16);
+ final BigInteger g = new BigInteger("2");
+ return new DHParameterSpec(p, g);
+ }
+
+ public DHParameterSpec ike2048() {
+ final BigInteger p =
+ new BigInteger(
+ "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+ + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+ + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+ + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+ + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+ + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b"
+ + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718"
+ + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff",
+ 16);
+ final BigInteger g = new BigInteger("2");
+ return new DHParameterSpec(p, g);
+ }
+
+ // The default parameters returned for 1024 bit DH keys from OpenJdk as defined in
+ // openjdk7/releases/v6/trunk/jdk/src/share/classes/sun/security/provider/ParameterCache.java
+ // I.e., these are the same parameters as used for DSA.
+ public DHParameterSpec openJdk1024() {
+ final BigInteger p =
+ new BigInteger(
+ "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
+ + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
+ + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
+ + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7",
+ 16);
+ final BigInteger unusedQ = new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16);
+ final BigInteger g =
+ new BigInteger(
+ "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
+ + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
+ + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
+ + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a",
+ 16);
+ return new DHParameterSpec(p, g);
+ }
+
+ /** Check that key agreement using DH works. */
+ public void testDh() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
+ DHParameterSpec dhparams = ike2048();
+ keyGen.initialize(dhparams);
+ KeyPair keyPairA = keyGen.generateKeyPair();
+ KeyPair keyPairB = keyGen.generateKeyPair();
+
+ KeyAgreement kaA = KeyAgreement.getInstance("DH");
+ KeyAgreement kaB = KeyAgreement.getInstance("DH");
+ kaA.init(keyPairA.getPrivate());
+ kaB.init(keyPairB.getPrivate());
+ kaA.doPhase(keyPairB.getPublic(), true);
+ kaB.doPhase(keyPairA.getPublic(), true);
+ byte[] kAB = kaA.generateSecret();
+ byte[] kBA = kaB.generateSecret();
+ assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA));
+ }
+
+ /**
+ * Returns the product of primes that can be found by a simple variant of Pollard-rho.
+ * The result should contain all prime factors of n smaller than 10^8.
+ * This method is heuristic, since it could in principle find large prime factors too.
+ * However, for a random 160-bit prime q the probability of this should be less than 2^{-100}.
+ */
+ private BigInteger smoothDivisor(BigInteger n) {
+ // By examination we verified that for every prime p < 10^8
+ // the iteration x_n = x_{n-1}^2 + 1 mod p enters a cycle of size < 50000 after at
+ // most 50000 steps.
+ int pollardRhoSteps = 50000;
+ BigInteger u = new BigInteger("2");
+ for (int i = 0; i < pollardRhoSteps; i++) {
+ u = u.multiply(u).add(BigInteger.ONE).mod(n);
+ }
+ BigInteger v = u;
+ BigInteger prod = BigInteger.ONE;
+ for (int i = 0; i < pollardRhoSteps; i++) {
+ v = v.multiply(v).add(BigInteger.ONE).mod(n);
+ // This implementation is only looking for the product of small primes.
+ // Therefore, instead of continuously computing gcds of v-u and n, it is sufficient
+ // and more efficient to compute the product of of v-u for all v and compute the gcd
+ // at the end.
+ prod = prod.multiply(v.subtract(u).abs()).mod(n);
+ }
+ BigInteger result = BigInteger.ONE;
+ while (true) {
+ BigInteger f = n.gcd(prod);
+ if (f.equals(BigInteger.ONE)) {
+ return result;
+ }
+ result = result.multiply(f);
+ n = n.divide(f);
+ }
+ }
+
+ @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE})
+ public void testKeyPair(KeyPair keyPair, int expectedKeySize) throws Exception {
+ DHPrivateKey priv = (DHPrivateKey) keyPair.getPrivate();
+ BigInteger p = priv.getParams().getP();
+ BigInteger g = priv.getParams().getG();
+ int keySize = p.bitLength();
+ assertEquals("wrong key size", keySize, expectedKeySize);
+
+ // Checks the key size of the private key.
+ // NIST SP 800-56A requires that x is in the range (1, q-1).
+ // Such a choice would require a full key validation. Since such a validation
+ // requires the value q (which is not present in the DH parameters) larger keys
+ // should be chosen to prevent attacks.
+ int minPrivateKeyBits = keySize / 2;
+ BigInteger x = priv.getX();
+ assertTrue(x.bitLength() >= minPrivateKeyBits - 32);
+ // TODO(bleichen): add tests for weak random number generators.
+
+ // Verify the DH parameters.
+ System.out.println("p=" + p.toString(16));
+ System.out.println("g=" + g.toString(16));
+ System.out.println("testKeyPairGenerator L=" + priv.getParams().getL());
+ // Basic parameter checks
+ assertTrue("Expecting g > 1", g.compareTo(BigInteger.ONE) > 0);
+ assertTrue("Expecting g < p - 1", g.compareTo(p.subtract(BigInteger.ONE)) < 0);
+ // Expecting p to be prime.
+ // No high certainty is needed, since this is a unit test.
+ assertTrue(p.isProbablePrime(4));
+ // The order of g should be a large prime divisor q of p-1.
+ // (see e.g. NIST SP 800-56A, section 5.5.1.1.)
+ // If the order of g is composite then the the Decision Diffie Hellman assumption is
+ // not satisfied for the group generated by g. Moreover, attacks using Pohlig-Hellman
+ // might be feasible.
+ // A good way to achieve these requirements is to select a safe prime p (i.e. a prime
+ // where q=(p-1)/2 is prime too. NIST SP 800-56A does not require (or even recommend)
+ // safe primes and allows Diffie-Hellman parameters where q is significantly smaller.
+ // Unfortunately, the key does not contain q and thus the conditions above cannot be
+ // tested easily.
+ // We perform a partial test that performs a partial factorization of p-1 and then
+ // test whether one of the small factors found by the partial factorization divides
+ // the order of g.
+ boolean isSafePrime = p.shiftRight(1).isProbablePrime(4);
+ System.out.println("p is a safe prime:" + isSafePrime);
+ BigInteger r; // p-1 divided by small prime factors.
+ if (isSafePrime) {
+ r = p.shiftRight(1);
+ } else {
+ BigInteger p1 = p.subtract(BigInteger.ONE);
+ r = p1.divide(smoothDivisor(p1));
+ }
+ System.out.println("r=" + r.toString(16));
+ assertEquals("g likely does not generate a prime oder subgroup", BigInteger.ONE,
+ g.modPow(r, p));
+
+ // Checks that there are not too many short prime factors.
+ // I.e., subgroup confinment attacks can find at least keySize - r.bitLength() bits of the key.
+ // At least 160 unknown bits should remain.
+ // Only very weak parameters are detected here, since the factorization above only finds small
+ // prime factors.
+ assertTrue(minPrivateKeyBits - (keySize - r.bitLength()) > 160);
+
+ // DH parameters are sometime misconfigures and g and q are swapped.
+ // A large g that divides p-1 is suspicious.
+ if (g.bitLength() >= 160) {
+ assertTrue(p.mod(g).compareTo(BigInteger.ONE) > 0);
+ }
+ }
+
+ /**
+ * Tests Diffie-Hellman key pair generation.
+ *
+ * <p> This is a slow test since some providers (e.g. BouncyCastle) generate new safe primes
+ * for each new key.
+ */
+ public void testKeyPairGenerator() throws Exception {
+ int keySize = 1024;
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
+ keyGen.initialize(keySize);
+ KeyPair keyPair = keyGen.generateKeyPair();
+ testKeyPair(keyPair, keySize);
+ }
+
+ /** This test tries a key agreement with keys using distinct parameters. */
+ public void testDHDistinctParameters() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
+ keyGen.initialize(ike1536());
+ KeyPair keyPairA = keyGen.generateKeyPair();
+
+ keyGen.initialize(ike2048());
+ KeyPair keyPairB = keyGen.generateKeyPair();
+
+ KeyAgreement kaA = KeyAgreement.getInstance("DH");
+ kaA.init(keyPairA.getPrivate());
+ try {
+ kaA.doPhase(keyPairB.getPublic(), true);
+ byte[] kAB = kaA.generateSecret();
+ fail("Generated secrets with mixed keys " + TestUtil.bytesToHex(kAB) + ", ");
+ } catch (java.security.GeneralSecurityException ex) {
+ // This is expected.
+ }
+ }
+
+ /**
+ * Tests whether a provider accepts invalid public keys that result in predictable shared secrets.
+ * This test is based on RFC 2785, Section 4 and NIST SP 800-56A, If an attacker can modify both
+ * public keys in an ephemeral-ephemeral key agreement scheme then it may be possible to coerce
+ * both parties into computing the same predictable shared key.
+ *
+ * <p> Note: the test is quite whimsical. If the prime p is not a safe prime then the provider
+ * itself cannot prevent all small-subgroup attacks because of the missing parameter q in the
+ * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones
+ * proposed in RFC 2785.
+ */
+ public void testSubgroupConfinement() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
+ DHParameterSpec params = ike2048();
+ BigInteger p = params.getP();
+ BigInteger g = params.getG();
+ keyGen.initialize(params);
+ PrivateKey priv = keyGen.generateKeyPair().getPrivate();
+ KeyAgreement ka = KeyAgreement.getInstance("DH");
+ BigInteger[] weakPublicKeys = {
+ BigInteger.ZERO,
+ BigInteger.ONE,
+ p.subtract(BigInteger.ONE),
+ p,
+ p.add(BigInteger.ONE),
+ BigInteger.ONE.negate()
+ };
+ for (BigInteger weakKey : weakPublicKeys) {
+ ka.init(priv);
+ try {
+ KeyFactory kf = KeyFactory.getInstance("DH");
+ DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g);
+ PublicKey pub = kf.generatePublic(weakSpec);
+ ka.doPhase(pub, true);
+ byte[] kAB = ka.generateSecret();
+ fail(
+ "Generated secrets with weak public key:"
+ + weakKey.toString()
+ + " secret:"
+ + TestUtil.bytesToHex(kAB));
+ } catch (GeneralSecurityException ex) {
+ // this is expected
+ }
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/DhiesTest.java b/java/com/google/security/wycheproof/testcases/DhiesTest.java
new file mode 100644
index 0000000..17ab513
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/DhiesTest.java
@@ -0,0 +1,157 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import com.google.security.wycheproof.WycheproofRunner.SlowTest;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.spec.DHParameterSpec;
+import junit.framework.TestCase;
+
+/**
+ * Testing DHIES.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// Tested providers:
+// BC (not recommended)
+//
+// TODO(bleichen):
+// - maybe again CipherInputStream, CipherOutputStream,
+// - byteBuffer.
+// - Exception handling
+// - Is DHIES using the key derivation function for the key stream?
+// - BouncyCastle knows an algorithm IES. Is this the same as DHIES?
+public class DhiesTest extends TestCase {
+
+ // TODO(bleichen): This is the same as DhTest.java
+ // We could move this into some TestUtil.
+ public DHParameterSpec ike2048() {
+ final BigInteger p =
+ new BigInteger(
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
+ 16);
+ final BigInteger g = new BigInteger("2");
+ return new DHParameterSpec(p, g);
+ }
+
+ /**
+ * WARNING: This test uses weak crypto (i.e. DHIESWithAES). Checks that key agreement using DHIES
+ * works in the sense that it can decrypt what it encrypts. Unfortunately it seems that there is
+ * no secure mode using AES.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testDhiesBasic() throws Exception {
+ DHParameterSpec params = ike2048();
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
+ kf.initialize(params);
+ KeyPair keyPair = kf.generateKeyPair();
+ PrivateKey priv = keyPair.getPrivate();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = "Hello".getBytes("UTF-8");
+ Cipher dhies = Cipher.getInstance("DHIESwithAES");
+ dhies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = dhies.doFinal(message);
+ System.out.println("testDhiesBasic:" + TestUtil.bytesToHex(ciphertext));
+ dhies.init(Cipher.DECRYPT_MODE, priv);
+ byte[] decrypted = dhies.doFinal(ciphertext);
+ assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
+ }
+
+ /**
+ * WARNING: This test uses weak crypto (i.e. DHIESWithAES). DHIES should be secure against chosen
+ * ciphertexts. Checks that a modification of the ciphertext is dectected.
+ */
+ @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE})
+ @SuppressWarnings("InsecureCipherMode")
+ public void testDhiesCorrupt() throws Exception {
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
+ kf.initialize(ike2048());
+ KeyPair keyPair = kf.generateKeyPair();
+ PrivateKey priv = keyPair.getPrivate();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = new byte[32];
+ Cipher dhies = Cipher.getInstance("DHIESwithAES");
+ dhies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = dhies.doFinal(message);
+ for (int i = 0; i < ciphertext.length; i++) {
+ byte[] corrupt = Arrays.copyOf(ciphertext, ciphertext.length);
+ corrupt[i] ^= (byte) 1;
+ try {
+ dhies.init(Cipher.DECRYPT_MODE, priv);
+ dhies.doFinal(corrupt);
+ fail("Corrupt ciphertext accepted:" + i);
+ } catch (GeneralSecurityException ex) {
+ // This is expected
+ }
+ }
+ }
+
+ /**
+ * Tries to detect if an algorithm is using ECB. Unfortunately, many JCE algorithms use ECB if no
+ * encryption mode is specified.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testNotEcb(String algorithm) throws Exception {
+ Cipher dhies;
+ try {
+ dhies = Cipher.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ // This test is called with short algorithm names such as just "DHIES".
+ // Requiring full names is typically a good practice. Hence it is OK
+ // to not assigning default algorithms.
+ System.out.println("No implementation for:" + algorithm);
+ return;
+ }
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
+ kf.initialize(ike2048());
+ KeyPair keyPair = kf.generateKeyPair();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = new byte[512];
+ dhies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = dhies.doFinal(message);
+ for (int i = 0; i + 32 <= ciphertext.length; i++) {
+ String block1 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, i, i + 16));
+ String block2 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, i + 16, i + 32));
+ assertTrue(
+ "Ciphertext repeats at " + i + ":" + TestUtil.bytesToHex(ciphertext),
+ !block1.equals(block2));
+ }
+ }
+
+ public void testSemanticSecurityDhies() throws Exception {
+ testNotEcb("DHIES");
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/DsaTest.java b/java/com/google/security/wycheproof/testcases/DsaTest.java
new file mode 100644
index 0000000..d2e4f94
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/DsaTest.java
@@ -0,0 +1,655 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(bleichen):
+// - add tests for SHA1WithDSA with wrong key
+// - add tests for "alternative" algorithm names
+// - convert tests for deterministic DSA variants.
+// Deterministic DSA has a few new drawbacks:
+// * implementations flaws that generate k incorrectly can leak
+// the key if multiple implementations (e.g. one correct one incorrect)
+// is used.
+// * timing attacks are more serious if the attacker can ask for the same
+// signature multiple times, since this allows to get more accurate timings.
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import com.google.security.wycheproof.WycheproofRunner.SlowTest;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import junit.framework.TestCase;
+
+/**
+ * Tests DSA against invalid signatures. The motivation for this test is the DSA implementation in
+ * gpg4browsers. This implementation accepts signatures with r=1 and s=0 as valid.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// Tested providers:
+// "SUN":
+// - allows some alternative BER encodings of signatures
+// - does not check whether the ASN sequence contains two elements
+// and throws runtime exceptions when the sequence is too short.
+// - does not support 3072 bit keys.
+// "BC":
+// - allows some alternaitve BER encodings
+// - accepts signatures with additional arguments
+// - key generation is slow, maybe because BouncyCastle tries to generate
+// new parameters for each key.
+// - KeyPairGenerator.getInstance("DSA") generates keys with 160 bit q
+// independent of the size of p.
+public class DsaTest extends TestCase {
+ static final String MESSAGE = "Hello";
+
+ static final DSAPrivateKeySpec privateKey1 =
+ new DSAPrivateKeySpec(
+ // x
+ new BigInteger("15382583218386677486843706921635237927801862255437148328980464126979"),
+ // p
+ new BigInteger(
+ "181118486631420055711787706248812146965913392568235070235446058914"
+ + "1170708161715231951918020125044061516370042605439640379530343556"
+ + "4101919053459832890139496933938670005799610981765220283775567361"
+ + "4836626483403394052203488713085936276470766894079318754834062443"
+ + "1033792580942743268186462355159813630244169054658542719322425431"
+ + "4088256212718983105131138772434658820375111735710449331518776858"
+ + "7867938758654181244292694091187568128410190746310049564097068770"
+ + "8161261634790060655580211122402292101772553741704724263582994973"
+ + "9109274666495826205002104010355456981211025738812433088757102520"
+ + "562459649777989718122219159982614304359"),
+ // q
+ new BigInteger("19689526866605154788513693571065914024068069442724893395618704484701"),
+ // g
+ new BigInteger(
+ "2859278237642201956931085611015389087970918161297522023542900348"
+ + "0877180630984239764282523693409675060100542360520959501692726128"
+ + "3149190229583566074777557293475747419473934711587072321756053067"
+ + "2532404847508798651915566434553729839971841903983916294692452760"
+ + "2490198571084091890169933809199002313226100830607842692992570749"
+ + "0504363602970812128803790973955960534785317485341020833424202774"
+ + "0275688698461842637641566056165699733710043802697192696426360843"
+ + "1736206792141319514001488556117408586108219135730880594044593648"
+ + "9237302749293603778933701187571075920849848690861126195402696457"
+ + "4111219599568903257472567764789616958430"));
+
+ static final DSAPublicKeySpec publicKey1 =
+ new DSAPublicKeySpec(
+ new BigInteger(
+ "3846308446317351758462473207111709291533523711306097971550086650"
+ + "2577333637930103311673872185522385807498738696446063139653693222"
+ + "3528823234976869516765207838304932337200968476150071617737755913"
+ + "3181601169463467065599372409821150709457431511200322947508290005"
+ + "1780020974429072640276810306302799924668893998032630777409440831"
+ + "4314588994475223696460940116068336991199969153649625334724122468"
+ + "7497038281983541563359385775312520539189474547346202842754393945"
+ + "8755803223951078082197762886933401284142487322057236814878262166"
+ + "5072306622943221607031324846468109901964841479558565694763440972"
+ + "5447389416166053148132419345627682740529"),
+ privateKey1.getP(),
+ privateKey1.getQ(),
+ privateKey1.getG());
+
+ // Signatures for Key1.
+ static final String[] VALID_SIGNATURES = {
+ "303d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ + "021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe8786236",
+ };
+
+ // The following test vectors check for signature malleability and bugs.
+ // That means the test vectors are derived from a valid signature
+ // by modifying the ASN encoding. A correct implementation of DSA
+ // should only accept correct DER encoding and properly handle the others.
+ // Allowing alternative BER encodings is in many cases benign.
+ // An example where this kind of signature malleability was a problem
+ // https://en.bitcoin.it/wiki/Transaction_Malleability
+
+ static final String[] INVALID_SIGNATURES = {
+ // encodings that were obtained by leaving some arguments out
+ "301f021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe87862" + "36",
+ "301e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd",
+ "",
+ // encodings that were obtained by leaving some parts empty
+ "30210200021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe8" + "786236",
+ "3020021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd" + "0200",
+ "3000",
+ // encodings with sizes that overflow 32 or 64 bit integers
+ "30420285010000001c1e41b479ad576905b960fe14eadb91b0ccf34843dab916"
+ + "173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ + "e8786236",
+ "3046028901000000000000001c1e41b479ad576905b960fe14eadb91b0ccf348"
+ + "43dab916173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ + "3365813fe8786236",
+ "3042021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ + "0285010000001d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ + "e8786236",
+ "3046021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ + "028901000000000000001d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ + "3365813fe8786236",
+ "3085010000003d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916"
+ + "173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ + "e8786236",
+ "308901000000000000003d021c1e41b479ad576905b960fe14eadb91b0ccf348"
+ + "43dab916173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ + "3365813fe8786236",
+ // encodings where numbers were replace by an encoding of infinity
+ "3022090180021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f" + "e8786236",
+ "3021021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd" + "090180",
+ // Signatures with special case values for r and s.
+ // E.g. r=1, s=0 are values that can lead to forgeries if the DSA implementation
+ // does not check boundaries and computes s^(-1) == 0.
+ "300402000200",
+ "30050200020101",
+ "300502000201ff",
+ "30210200021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc" + "d5695d",
+ "30210200021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc" + "d5695e",
+ "30210200021d0100000000000000000000000000000000000000000000000000" + "000000",
+ "30820107020002820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3b"
+ + "af3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85"
+ + "d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9934534"
+ + "09a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d"
+ + "648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d81"
+ + "81e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f80"
+ + "3b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b"
+ + "66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342"
+ + "be484c05763939601cd667",
+ "30070200090380fe01",
+ "30050201010200",
+ "3006020101020101",
+ "30060201010201ff",
+ "3022020101021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695d",
+ "3022020101021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695e",
+ "3022020101021d01000000000000000000000000000000000000000000000000" + "00000000",
+ "3082010802010102820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e"
+ + "3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b"
+ + "85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a99345"
+ + "3409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f"
+ + "9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d"
+ + "8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f"
+ + "803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de"
+ + "4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e3"
+ + "42be484c05763939601cd667",
+ "3008020101090380fe01",
+ "30050201ff0200",
+ "30060201ff020101",
+ "30060201ff0201ff",
+ "30220201ff021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695d",
+ "30220201ff021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695e",
+ "30220201ff021d01000000000000000000000000000000000000000000000000" + "00000000",
+ "308201080201ff02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e"
+ + "3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b"
+ + "85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a99345"
+ + "3409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f"
+ + "9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d"
+ + "8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f"
+ + "803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de"
+ + "4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e3"
+ + "42be484c05763939601cd667",
+ "30080201ff090380fe01",
+ "3021021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d0200",
+ "3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d020101",
+ "3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d0201ff",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5d021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5d021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5d021d0100000000000000000000000000000000000000000000000000000000",
+ "30820124021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc"
+ + "d5695d02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ + "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ + "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ + "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ + "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ + "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ + "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ + "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ + "05763939601cd667",
+ "3024021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d090380fe01",
+ "3021021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e0200",
+ "3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e020101",
+ "3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e0201ff",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
+ "303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ + "5e021d0100000000000000000000000000000000000000000000000000000000",
+ "30820124021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc"
+ + "d5695e02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ + "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ + "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ + "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ + "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ + "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ + "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ + "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ + "05763939601cd667",
+ "3024021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e090380fe01",
+ "3021021d01000000000000000000000000000000000000000000000000000000" + "000200",
+ "3022021d01000000000000000000000000000000000000000000000000000000" + "00020101",
+ "3022021d01000000000000000000000000000000000000000000000000000000" + "000201ff",
+ "303e021d01000000000000000000000000000000000000000000000000000000"
+ + "00021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
+ "303e021d01000000000000000000000000000000000000000000000000000000"
+ + "00021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
+ "303e021d01000000000000000000000000000000000000000000000000000000"
+ + "00021d0100000000000000000000000000000000000000000000000000000000",
+ "30820124021d0100000000000000000000000000000000000000000000000000"
+ + "00000002820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ + "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ + "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ + "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ + "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ + "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ + "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ + "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ + "05763939601cd667",
+ "3024021d01000000000000000000000000000000000000000000000000000000" + "00090380fe01",
+ "3082010702820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd6670200",
+ "3082010802820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd667020101",
+ "3082010802820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd6670201ff",
+ "3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd667021d00baf696a68578f7dfdee7fa67c977c785ef32b233"
+ + "bae580c0bcd5695d",
+ "3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd667021d00baf696a68578f7dfdee7fa67c977c785ef32b233"
+ + "bae580c0bcd5695e",
+ "3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd667021d010000000000000000000000000000000000000000"
+ + "0000000000000000",
+ "3082020a02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd66702820101008f7935d9b9aae9bfabed887acf4951b6f32e"
+ + "c59e3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7"
+ + "475b85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9"
+ + "93453409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6"
+ + "291f9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9f"
+ + "fa9d8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633"
+ + "458f803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea1"
+ + "43de4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f8"
+ + "22e342be484c05763939601cd667",
+ "3082010a02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ + "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ + "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ + "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ + "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ + "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ + "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ + "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ + "4c05763939601cd667090380fe01",
+ "3007090380fe010200",
+ "3008090380fe01020101",
+ "3008090380fe010201ff",
+ "3024090380fe01021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae5" + "80c0bcd5695d",
+ "3024090380fe01021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae5" + "80c0bcd5695e",
+ "3024090380fe01021d0100000000000000000000000000000000000000000000" + "000000000000",
+ "3082010a090380fe0102820101008f7935d9b9aae9bfabed887acf4951b6f32e"
+ + "c59e3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7"
+ + "475b85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9"
+ + "93453409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6"
+ + "291f9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9f"
+ + "fa9d8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633"
+ + "458f803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea1"
+ + "43de4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f8"
+ + "22e342be484c05763939601cd667",
+ "300a090380fe01090380fe01",
+ };
+
+ public void testVectors(
+ String[] signatures,
+ DSAPublicKeySpec key,
+ String message,
+ String algorithm,
+ String signatureType,
+ boolean isValid)
+ throws Exception {
+ byte[] messageBytes = "Hello".getBytes("UTF-8");
+ Signature verifier = Signature.getInstance(algorithm);
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ PublicKey pub = kf.generatePublic(key);
+ int errors = 0;
+ for (String signature : signatures) {
+ byte[] signatureBytes = TestUtil.hexToBytes(signature);
+ verifier.initVerify(pub);
+ verifier.update(messageBytes);
+ boolean verified = false;
+ try {
+ verified = verifier.verify(signatureBytes);
+ } catch (SignatureException ex) {
+ // verify can throw SignatureExceptions if the signature is malformed.
+ // We don't flag these cases and simply consider the signature as invalid.
+ verified = false;
+ } catch (Exception ex) {
+ // Other exceptions indicate some internal error, e.g. careless ASN parsing.
+ // We count these as errors.
+ System.out.println(signatureType + ":" + signature + " throws:" + ex.toString());
+ errors++;
+ continue;
+ }
+ if (isValid && !verified) {
+ System.out.println(signatureType + " was not verified:" + signature);
+ errors++;
+ } else if (!isValid && verified) {
+ System.out.println(signatureType + " was verified:" + signature);
+ errors++;
+ }
+ }
+ assertEquals(0, errors);
+ }
+
+ public void testValidSignatures() throws Exception {
+ testVectors(
+ VALID_SIGNATURES, publicKey1, "Hello", "SHA224WithDSA", "Valid DSA signature", true);
+ }
+
+ // Extract the integer r from a DSA signature.
+ // This method implicitely assumes that the DSA signature is DER encoded.
+ BigInteger extractR(byte[] signature) throws Exception {
+ int lengthR = signature[3];
+ return new BigInteger(Arrays.copyOfRange(signature, 4, 4 + lengthR));
+ }
+
+ BigInteger extractS(byte[] signature) throws Exception {
+ int lengthR = signature[3];
+ int startS = 4 + lengthR;
+ int lengthS = signature[startS + 1];
+ return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
+ }
+
+ /** Extract the k that was used to sign the signature. Validates the k if check == true. */
+ BigInteger extractK(byte[] signature, BigInteger h, DSAPrivateKey priv, boolean check)
+ throws Exception {
+ BigInteger x = priv.getX();
+ BigInteger q = priv.getParams().getQ();
+ BigInteger r = extractR(signature);
+ BigInteger s = extractS(signature);
+ BigInteger k = x.multiply(r).add(h).multiply(s.modInverse(q)).mod(q);
+ if (check) {
+ BigInteger p = priv.getParams().getP();
+ BigInteger g = priv.getParams().getG();
+ BigInteger r2 = g.modPow(k, p).mod(q);
+ assertEquals(r.toString(), r2.toString());
+ }
+ return k;
+ }
+
+ /**
+ * Providers that implement SHA1WithDSA but not at least SHA256WithDSA are outdated and should be
+ * avoided even if DSA is currently not used in a project. Such providers promote using a weak
+ * signature scheme. It can also "inspire" developers to use invalid schemes such as SHA1WithDSA
+ * together with 2048-bit key. Such invalid use cases are often untested and can have serious
+ * flaws. For example the SUN provider leaked the private keys with 3 to 5 signatures in such
+ * instances.
+ */
+ public void testOutdatedProvider() throws Exception {
+ try {
+ Signature sig = Signature.getInstance("SHA1WithDSA");
+ try {
+ Signature.getInstance("SHA256WithDSA");
+ } catch (NoSuchAlgorithmException ex) {
+ fail("Provider " + sig.getProvider().getName() + " is outdated and should not be used.");
+ }
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("SHA1WithDSA is not supported");
+ }
+ }
+
+ /**
+ * This is just a test for basic functionality of DSA. The test generates a public and private
+ * key, generates a signature, verifies it and prints the whole thing out. This test is useful
+ * when an implementation is seriously broken.
+ */
+ @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE})
+ public void testBasic() throws Exception {
+ int keySize = 2048;
+ String algorithm = "SHA256WithDSA";
+ String hashAlgorithm = "SHA-256";
+ String message = "Hello";
+
+ byte[] messageBytes = message.getBytes("UTF-8");
+ KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
+ generator.initialize(keySize);
+ KeyPair keyPair = generator.generateKeyPair();
+ DSAPublicKey pub = (DSAPublicKey) keyPair.getPublic();
+ DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
+ Signature signer = Signature.getInstance(algorithm);
+ Signature verifier = Signature.getInstance(algorithm);
+ signer.initSign(priv);
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ verifier.initVerify(pub);
+ verifier.update(messageBytes);
+ assertTrue(verifier.verify(signature));
+
+ // Extract some parameters.
+ byte[] rawHash = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+ DSAParams params = priv.getParams();
+
+ // Print keys and signature, so that it can be used to generate new test vectors.
+ System.out.println("Message:" + message);
+ System.out.println("Hash:" + TestUtil.bytesToHex(rawHash));
+ System.out.println("Params:");
+ System.out.println("p:" + params.getP().toString());
+ System.out.println("q:" + params.getQ().toString());
+ System.out.println("g:" + params.getG().toString());
+ System.out.println("Private key:");
+ System.out.println("X:" + priv.getX().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
+ System.out.println("Public key:");
+ System.out.println("Y:" + pub.getY().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
+ System.out.println("Signature:" + TestUtil.bytesToHex(signature));
+ System.out.println("r:" + extractR(signature).toString());
+ System.out.println("s:" + extractS(signature).toString());
+ }
+
+ /**
+ * Checks whether the one time key k in DSA is biased. For example the SUN provider fell for this
+ * test until April 2016.
+ */
+ public void testDsaBias() throws Exception {
+ // q is close to 2/3 * 2^160.
+ BigInteger q = new BigInteger("974317976835659416858874959372334979171063697271");
+ BigInteger p =
+ new BigInteger(
+ "1106803511314772711673172950296693567629309594518393175860816428"
+ + "6658764043763662129010863568011543182924292444458455864283745070"
+ + "9908516713302345161980412667892373845670780253725557376379049862"
+ + "4062950082444499320797079243439689601679418602390654466821968220"
+ + "32212146727497041502702331623782703855119908989712161");
+ BigInteger g =
+ new BigInteger(
+ "1057342118316953575810387190942009018497979302261477972033090351"
+ + "7561815639397594841480480197745063606756857212792356354588585967"
+ + "3837265237205154744016475608524531648654928648461175919672511710"
+ + "4878976887505840764543501512668232945506391524642105449699321960"
+ + "32410302985148400531470153936516167243072120845392903");
+ BigInteger x = new BigInteger("13706102843888006547723575730792302382646994436");
+
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPrivateKey priv = (DSAPrivateKey) kf.generatePrivate(new DSAPrivateKeySpec(x, p, q, g));
+
+ // If we make TESTS tests with a fair coin then the probability that
+ // either heads or tails appears less than MINCOUNT times is less than
+ // 2^{-32}.
+ // I.e. 2*sum(binomial(tests,i) for i in range(mincount))*2**32 < 2**tests
+ // Therefore the test below is not expected to fail unless the generation
+ // of the one time keys is indeed biased.
+ final int tests = 1024;
+ final int mincount = 410;
+
+ String hashAlgorithm = "SHA";
+ String message = "Hello";
+ byte[] messageBytes = message.getBytes("UTF-8");
+ byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+ BigInteger h = new BigInteger(1, digest);
+
+ final BigInteger qHalf = q.shiftRight(1);
+ Signature signer = Signature.getInstance("SHA1WithDSA");
+ signer.initSign(priv);
+ int countLsb = 0; // count the number of k's with msb set
+ int countMsb = 0; // count the number of k's with lsb set
+ for (int i = 0; i < tests; i++) {
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ BigInteger k = extractK(signature, h, priv, i < 10);
+ if (k.testBit(0)) {
+ countLsb++;
+ }
+ if (k.compareTo(qHalf) == 1) {
+ countMsb++;
+ }
+ }
+ if (countLsb < mincount || countLsb > tests - mincount) {
+ fail("Bias detected in the least significant bit of k:" + countLsb);
+ }
+ if (countMsb < mincount || countMsb > tests - mincount) {
+ fail("Bias detected in the most significant bit of k:" + countMsb);
+ }
+ }
+
+ /**
+ * Checks whether CVE-2016-0695 has been fixed. Before the April 2016 security update, the SUN
+ * provider had a serious flaw that leaked the private key with about 3-5 signatures. In
+ * particular, "Sha1WithDSA" always generated 160 bit k's independently of q. Unfortunately, it is
+ * easily possible to use 2048 and 3072 bit DSA keys together with SHA1WithDSA. All a user has to
+ * do is to use the algorithm name "DSA" instead of "SHA256WithDSA" rsp. "SHA224WithDSA".
+ *
+ * <p>An algorithm to extract the key from the signatures has been described for example in the
+ * paper <a href="http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf">Lattice Attacks on
+ * Digital Signature Schemes</a> by N.A. Howgrave-Graham, N.P. Smart.
+ *
+ * <p>This bug is the same as US-CERT: VU # 940388: GnuPG generated ElGamal signatures that leaked
+ * the private key.
+ */
+ @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE})
+ public void testBiasSha1WithDSA() throws Exception {
+ String hashAlgorithm = "SHA";
+ String message = "Hello";
+ byte[] messageBytes = message.getBytes("UTF-8");
+ byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+ BigInteger h = new BigInteger(1, digest);
+
+ KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
+ generator.initialize(2048);
+ KeyPair keyPair = generator.generateKeyPair();
+ DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
+ Signature signer = Signature.getInstance("DSA");
+ try {
+ // Private key and selected algorithm by signer do not match.
+ // Hence throwing an exception at this point would be the reasonable.
+ signer.initSign(priv);
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ BigInteger q = priv.getParams().getQ();
+ BigInteger k = extractK(signature, h, priv, true);
+
+ // Now check if k is heavily biased.
+ int lengthDiff = q.bitLength() - k.bitLength();
+ if (lengthDiff > 32) {
+ fail(
+ "Severly biased DSA signature:"
+ + " len(q)="
+ + q.bitLength()
+ + " len(k)="
+ + k.bitLength());
+ }
+ } catch (GeneralSecurityException ex) {
+ // The key is invalid, hence getting here is reasonable.
+ return;
+ }
+ }
+
+ /**
+ * DSA does not allow encryption. This test verifies that a provider does not implement an ad hoc
+ * scheme that attempts to turn DSA into a public key encryption scheme.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testEncryptionWithDsa() throws Exception {
+ try {
+ Cipher cipher = Cipher.getInstance("DSA");
+ fail("DSA must not be used as a cipher:" + cipher.getProvider().toString());
+ } catch (NoSuchAlgorithmException ex) {
+ // This is expected
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/EcKeyTest.java b/java/com/google/security/wycheproof/testcases/EcKeyTest.java
new file mode 100644
index 0000000..8d3563c
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/EcKeyTest.java
@@ -0,0 +1,230 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(bleichen): RFC 3279 allows ECKeys with a number of different parameters.
+// E.g. public keys can specify the order, base points etc.
+// We might want to check how well these parameters are verified when parsing
+// a public key.
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import junit.framework.TestCase;
+
+/** EC tests */
+public class EcKeyTest extends TestCase {
+ /**
+ * Encodings of public keys with invalid parameters. There are multiple places where a provider
+ * can validate a public key: some parameters are typically validated by the KeyFactory, more
+ * validation can be done by the cryptographic primitive. Unused parameters are sometimes not
+ * validated at all.
+ *
+ * <p>This following test vectors are public key encodings with invalid parameters where we expect
+ * that KeyFactory.generatePublic recognizes the problem. The documentation simply claims that an
+ * InvalidKeySpecException is thrown if the given key specification is inappropriate but does not
+ * specify what an appropriate key exactly is. Nonetheless we expect that the following minimal
+ * validations are performed: order is a positive integer, cofactor is a small positive integer.
+ * Some modifications may not be detected and must be caught by the primitives using them. E.g.,
+ * it is expensive to verify the order of the group generated by the generator and hence the key
+ * factory may not verify the correctness of this parameter. Thus an implementation of ECDH must
+ * not trust an order claimed in the public key.
+ *
+ * <p>TODO(bleichen): The encoding is defined in https://tools.ietf.org/html/rfc3279 Section
+ * 2.3.5. This document defines a few additional requirements and options which are not yet
+ * checked: - OID for id-public-key_type must be ansi-X9.62 2 - OID for id-ecPublicKey must be
+ * id-publicKeyType 1 - The intended application for the key may be indicated in the key usage
+ * field (RFC 3280). - EcpkParameters can be implicitlyCA (not sure how we would specify the curve
+ * in this case) - the version is always 1 - the points on the curves can be either compressed or
+ * uncompressed (so far all points are uncompressed) - the seed value is optional (so far no test
+ * vector specifies the seed) - the cofactor is optional but must be included for ECDH keys. (so
+ * far all test vectors have a cofactor)
+ *
+ * <p>RFC 3279 also specifies curves over binary fields. Because of attacks against such curves,
+ * i.e. "New algorithm for the discrete logarithm problem on elliptic curves" by I.Semaev
+ * https://eprint.iacr.org/2015/310 such curves should no longer be used and hence testing them
+ * has low priority.
+ */
+ public static final String[] EC_INVALID_PUBLIC_KEYS = {
+ // order = -115792089210356248762697446949407573529996955224135760342422259061068512044369
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f50221ff00000000ffffffff0000000000000000"
+ + "4319055258e8617b0c46353d039cdaaf02010103420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ // order = 0
+ "308201123081cb06072a8648ce3d02013081bf020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5020002010103420004cdeb39edd03e2b1a11a5"
+ + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ // cofactor = -1
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc6325510201ff03420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ // cofactor = 0
+ "308201323081eb06072a8648ce3d02013081df020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc632551020003420004cdeb39edd03e2b1a11a5"
+ + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ // cofactor = 115792089210356248762697446949407573529996955224135760342422259061068512044369
+ "308201553082010d06072a8648ce3d020130820100020101302c06072a8648ce"
+ + "3d0101022100ffffffff00000001000000000000000000000000ffffffffffff"
+ + "ffffffffffff30440420ffffffff00000001000000000000000000000000ffff"
+ + "fffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0"
+ + "cc53b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277"
+ + "037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162b"
+ + "ce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffff"
+ + "ffffbce6faada7179e84f3b9cac2fc632551022100ffffffff00000000ffffff"
+ + "ffffffffffbce6faada7179e84f3b9cac2fc63255103420004cdeb39edd03e2b"
+ + "1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b842959"
+ + "8c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ };
+
+ public void testEncodedPublicKey() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ for (String encodedHex : EC_INVALID_PUBLIC_KEYS) {
+ byte[] encoded = TestUtil.hexToBytes(encodedHex);
+ X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(encoded);
+ try {
+ ECPublicKey unused = (ECPublicKey) kf.generatePublic(x509keySpec);
+ fail("Constructed invalid public key from:" + encodedHex);
+ } catch (InvalidKeySpecException ex) {
+ // OK, since the public keys have been modified.
+ System.out.println(ex.toString());
+ }
+ }
+ }
+
+ public void testEncodedPrivateKey() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(EcUtil.getNistP256Params());
+ KeyPair keyPair = keyGen.generateKeyPair();
+ ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
+ byte[] encoded = priv.getEncoded();
+ System.out.println("Encoded ECPrivateKey:" + TestUtil.bytesToHex(encoded));
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPrivateKey decoded = (ECPrivateKey) kf.generatePrivate(spec);
+ assertEquals(priv.getS(), decoded.getS());
+ assertEquals(priv.getParams().getCofactor(), decoded.getParams().getCofactor());
+ assertEquals(priv.getParams().getCurve(), decoded.getParams().getCurve());
+ assertEquals(priv.getParams().getGenerator(), decoded.getParams().getGenerator());
+ assertEquals(priv.getParams().getOrder(), decoded.getParams().getOrder());
+ }
+
+ /**
+ * Tests key generation for given parameters. The test can be skipped if the curve is not a
+ * standard curve.
+ */
+ void testKeyGeneration(ECParameterSpec ecParams, boolean isStandard) throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ KeyPair keyPair;
+ try {
+ keyGen.initialize(ecParams);
+ keyPair = keyGen.generateKeyPair();
+ } catch (InvalidAlgorithmParameterException ex) {
+ if (!isStandard) {
+ return;
+ }
+ throw ex;
+ }
+ ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
+ ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
+ EcUtil.checkPublicKey(pub);
+ BigInteger s = priv.getS();
+ // Check the length of s. Could fail with probability 2^{-32}.
+ assertTrue(s.bitLength() >= EcUtil.fieldSizeInBits(ecParams.getCurve()) - 32);
+ // TODO(bleichen): correct curve?
+ // TODO(bleichen): use RandomUtil
+ }
+
+ public void testKeyGenerationAll() throws Exception {
+ testKeyGeneration(EcUtil.getNistP224Params(), true);
+ testKeyGeneration(EcUtil.getNistP256Params(), true);
+ testKeyGeneration(EcUtil.getNistP384Params(), true);
+ testKeyGeneration(EcUtil.getNistP521Params(), true);
+ // Curves that are sometimes not supported.
+ testKeyGeneration(EcUtil.getBrainpoolP256r1Params(), false);
+ }
+
+ /**
+ * Checks that the default key size for ECDSA is up to date.
+ * The test uses NIST SP 800-57 part1 revision 4, Table 2, page 53
+ * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf
+ * for the minimal key size of EC keys.
+ * Nist recommends a minimal security strength of 112 bits for the time until 2030.
+ * To achieve this security strength EC keys of at least 224 bits are required.
+ */
+ public void testDefaultKeyGeneration() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ KeyPair keyPair = keyGen.generateKeyPair();
+ ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
+ int keySize = EcUtil.fieldSizeInBits(pub.getParams().getCurve());
+ if (keySize < 224) {
+ fail("Expected a default key size of at least 224 bits. Size of generate key is " + keySize);
+ }
+ }
+
+ /**
+ * Tries to generate a public key with a point at infinity. Public keys with a point at infinity
+ * should be rejected to prevent subgroup confinement attacks.
+ */
+ public void testPublicKeyAtInfinity() throws Exception {
+ ECParameterSpec ecSpec = EcUtil.getNistP256Params();
+ try {
+ ECPublicKeySpec pubSpec = new ECPublicKeySpec(ECPoint.POINT_INFINITY, ecSpec);
+ fail(
+ "Point at infinity is not a valid public key. "
+ + pubSpec.getW().equals(ECPoint.POINT_INFINITY));
+ } catch (java.lang.IllegalArgumentException ex) {
+ // This is expected
+ }
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/EcdhTest.java b/java/com/google/security/wycheproof/testcases/EcdhTest.java
new file mode 100644
index 0000000..4094f41
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/EcdhTest.java
@@ -0,0 +1,1125 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import javax.crypto.KeyAgreement;
+import junit.framework.TestCase;
+
+/**
+ * Testing ECDH.
+ *
+ * <p><b>Defense in depth</b>: The tests for ECDH assume that a attacker has control over all
+ * aspects of the public key in an exchange. That means that the attacker can potentially send weak
+ * or invalid public keys. For example, invalid public keys can contain points not on the curve,
+ * curves that have been deliberately chosen so that DLs are easy to compute as well as orders or
+ * cofactors that are wrong. It is expected that implementations validate the inputs of a key
+ * agreement and that in no case information about the private key is leaked.
+ *
+ * <p><b>References:</b> Ingrid Biehl, Bernd Meyer, Volker Müller, "Differential Fault Attacks on
+ * Elliptic Curve Cryptosystems", Crypto '00, pp. 131-164
+ *
+ * <p>Adrian Antipa, Daniel Brown, Alfred Menezes, Rene Struik, and Scott Vanstone, "Validation of
+ * Elliptic Curve Public Keys", PKC 2003, https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
+ *
+ * <p># <b>Bugs:</b> CVE-2015-7940: BouncyCastle before 1.51 does not validate a point is on the
+ * curve. BouncyCastle v.1.52 checks that the public key point is on the public key curve but does
+ * not check whether public key and private key use the same curve. BouncyCastle v.1.53 is still
+ * vulnerable to attacks with modified public keys. An attacker can change the order of the curve
+ * used by the public key. ECDHC would then reduce the private key modulo this order, which can be
+ * used to find the private key.
+ *
+ * <p>SunEC had similar problem. CVE ?
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// TODO(bleichen): Stuff we haven't implemented:
+// - timing attacks
+// Stuff we are delaying because there are more important bugs:
+// - testWrongOrder using BouncyCastle with ECDHWithSHA1Kdf throws
+// java.lang.UnsupportedOperationException: KDF can only be used when algorithm is known
+// Not sure if that is expected or another bug.
+// CVEs for ECDH we haven't used anywhere.
+// - CVE-2014-3470: OpenSSL anonymous ECDH denial of service: triggered by NULL value in
+// certificate.
+// - CVE-2014-3572: OpenSSL downgrades ECDHE to ECDH
+// - CVE-2011-3210: OpenSSL was not thread safe
+public class EcdhTest extends TestCase {
+
+ static final String[] ECDH_VARIANTS = {
+ // Raw ECDH. The shared secret is the x-coordinate of the ECDH computation.
+ // The tests below assume that this variant is implemenented.
+ "ECDH",
+ // ECDHC is a variant described in P1363 7.2.2 ECSVDP-DHC.
+ // BouncyCastle implements this variant.
+ "ECDHC",
+ // A variant with an explicit key derivation function.
+ // This is implemented by BouncyCastle.
+ "ECDHWITHSHA1KDF",
+ };
+
+ /** ECDH test vectors */
+ public static class EcdhTestVector {
+ final String curvename;
+ final String pub; // hexadecimal representation of the X509 encoding
+ final BigInteger s; // private key
+ final String shared; // hexadecimal representation of the shared secret
+
+ public EcdhTestVector(String curvename, String pub, BigInteger s, String shared) {
+ this.curvename = curvename;
+ this.pub = pub;
+ this.s = s;
+ this.shared = shared;
+ }
+
+ public ECPublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ byte[] encoded = TestUtil.hexToBytes(pub);
+ return (ECPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+
+ public ECPrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPrivateKeySpec spec = new ECPrivateKeySpec(s, EcUtil.getCurveSpecRef(curvename));
+ return (ECPrivateKey) kf.generatePrivate(spec);
+ }
+ }
+
+ public static final EcdhTestVector[] ECDH_TEST_VECTORS = {
+ // vectors with normal ECDH values
+ new EcdhTestVector(
+ "secp224r1",
+ "304e301006072a8648ce3d020106052b81040021033a00049c08bb3788a5cb8d"
+ + "22591f2520791cdaf61765a84f0419d28ff8fb2dcb5d51e5714d8740420d0945"
+ + "187f97be42872bae9bf3f5b1857a475f",
+ new BigInteger("8af784fe9cebd363df85f598dcc2ab82b2ca725360dadb77b3708032", 16),
+ "c1921af3d06d813ccb009e363a647836d30b3f9c211c26e64a3bb0b6"),
+ new EcdhTestVector(
+ "secp256r1",
+ "3059301306072a8648ce3d020106082a8648ce3d030107034200044b3b0a5231"
+ + "76309f259498c55e3a9be45c9fb65ad4e60d6064e04b89c1bd0a1835039219c1"
+ + "22b89e2b539bb16d3afced502137f02944c374863137035fd3f1ae",
+ new BigInteger("051a995be2a8499e2c9331b3b5f3c012048bb02a1a6f044ed93d9bd295fcec16", 16),
+ "33befba428b295b9a0123d3a848d91d1e9a5266959e036d1a25e28d83d06421f"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b8104002203620004c1d31b771bb123f4"
+ + "fb2b789a2880c57a68b3bbfa7da3d80b8325b73428bd2a4e79b55b57ac454f52"
+ + "8ac02b62d54dfc315b9ba04363e94b825767951a9338f5d1db4c6d3f0e9a15bc"
+ + "9b834fc11a01e4b310c22aba73766fd769ea684fbad5d9d2",
+ new BigInteger("ff65a2bf5e1347e2286fb29273fb118a76996038bea2fcfd2032e8663f7588e5"
+ + "3130d195b161eba39085abbc3e24bcef", 16),
+ "dbd85b2caaca6d69460c94bd9f99b3bd51404788a58334a18709a882050fe1bf"
+ + "a4dd74de6e4368c1243443e5f64b60c7"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000401ca6ec5476b"
+ + "ae3cf0f28f370ac3a9a0de2091418a590978bf87a6f1aeadebde98925e8fb42c"
+ + "d03d57ff9aeb9890646067a3095874828a392b80a88880e5f456e4d000493581"
+ + "376d20d711a487e0106a3fc047b91803ed154e274b26d858cf2f55e356b45765"
+ + "2101b925b7d36b542d2a3e33e01404fb4f944c3b8ef276b6f5082e591135",
+ new BigInteger("01f362c182f1eaae2920578a2f30c228e28b996e74d4bd799621300d5f2e6c69"
+ + "30204f00476732c95a79ae527503621edf633dbb87400740f54adc4430706221"
+ + "2f68", 16),
+ "0107b9c99c80e2bc834e10c44afe2d611aafe8aad0eb80384aefbd9bb8196ea3"
+ + "b5797bedac39de3362532c9b04aeb98a3e60034c3d2dcb4a43b8f8b44e9528d3"
+ + "eeb8"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a7020101034200048178776ff8332108da"
+ + "d4fa59bce3111133a30e33fa7f96d0211ec9fa4904dcca084de67f52fd720ccd"
+ + "ada5c49305200a6028793a83cbe692c08237ecd0572fa2",
+ new BigInteger("143be522a9d0420f6bd19b95ce3a5e19c61970c31f13448276546625e607e7c9", 16),
+ "3658b819481f00f74cfd76b9dcf82867c3c3186f948cbc75bf296c6d332aedf0"),
+ // vectors with extreme values for the shared secret
+ new EcdhTestVector(
+ "secp256r1",
+ "3059301306072a8648ce3d020106082a8648ce3d03010703420004983f80374a"
+ + "4730f9decd7221fa3ebb527d44f459b6c6afcf7de7069481400a748fb8733ba0"
+ + "8e01cd53d54af45975554d0dbd6d5f0acf0fd95692606347cace7e",
+ new BigInteger("56556c546751dee664ae71baa0189a2e69b1e1f8939a49ed7cc35d7ea98fbcc7", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b8104002203620004d64af08419f8a0aa"
+ + "5d830a2b0f42e6a27a3c17e0e98f64a1e7e10c6a41a308832dcd9a493db0cd43"
+ + "7e47063c1db6c967494c8460f03bf95ff619b7c7499e1bc08fd759fc44c4af3d"
+ + "03de541a719baf996b4f91a9af5bf08fa671af0899f91359",
+ new BigInteger("ee383acde7e5b3e6c246833e183c4272a1714a13097b4b57bc2eeecdccbd69b6"
+ + "cff435215a3c92b5d4e0b2c36444a7fa", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ + "00000000000000000000000000000000"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b81040022036200041c1ed3f66b6ae370"
+ + "411ac30fda63c784c5cbc3951a7cfe567d8bfa3ea535a2eb8c192d349e69ea2a"
+ + "39eb5013a5cf383cf91c82e81eee1a9bc97386e340e65b2b2d8cf2633b919a82"
+ + "10a638b8e2345cda054ce96efcaeee20dcce82d13d40eb6a",
+ new BigInteger("98f230ef0c0ab02c78179ba9ea3e1c8d16c3ec276665c432b9040b803dfff657"
+ + "a6c77512b6a602d416785016c3cd3da7", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ + "00000000000000000000000000000002"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b8104002203620004d10b0df120b1324d"
+ + "8b76ee43065e4f4be63f68cf5b381ae79046920108a8f21cf8097bf313225b74"
+ + "1125eb5a66105ee445961b28ad1843613775c063a85319f1353d8bf2a217210e"
+ + "309f2c7c27b57d42fdc042abb00b37a0f3118cf74b4174f0",
+ new BigInteger("5b8e9af3c17fa0d683f3bc94f8685f33c0b616281f91b466cac9da0a0e085ba6"
+ + "f48aafcdb4fc13d55f1a33ac436f82bb", 16),
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+ + "ffffffff0000000000000000fffffffe"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b810400230381860004008269c7d0ff"
+ + "febadbf5bdfa2adf0f378d0844268e5acb57d0157fe688488cef91256e15939d"
+ + "311aaf6479e29ef14de3981c3a5768c7b66693e956fa515d4a0c847c0054a32b"
+ + "4a8f615ba5550f204ebf1f7f02f7252b5ae564361eec468adf4d59caa4c4b424"
+ + "a30761d805d521c2e1f1dfde385e9146624cb2b84f94888730acbfbf1294",
+ new BigInteger("019ad2de5943f5112021a3215cee84c4e8d40e188641419a5b7958636f1843d0"
+ + "cbda4747aad69fd806b333b82b095d0f10bda8dbeca7ee9f67d09caffb4869e4"
+ + "1172", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0000"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b810400230381860004003b0d698705"
+ + "0fad0f76ac1ac7a1c7e91e24addf821c06ae0844a3f1b6338c111a32a94a5369"
+ + "fdf8fd1cc137314c7d7a99dfabba1cc92f10026e45388714fe453ed50015e59a"
+ + "c4bab161635e0df0f5553ee6112fc60f744ffc607965975c0843f7a893441c4f"
+ + "e5e6e290426dd219ecbc159f39302b52b37b69a890e9fc4cf70eba39bbf6",
+ new BigInteger("0147492d3019808024569dc81b0e6aef9f27bfd43e009e8b4b6b0512b220490e"
+ + "08f98324b16d3ed91a54d391f92973f5376c66b9f8a9cbf893b0900968fd8d6e"
+ + "5e7d", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0001"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000401bb2936bfc5"
+ + "8f1e9819d62ed2a38a0ce618f000546fe8af4983d8dbbda7b7ae914a656ac540"
+ + "7c153f6edacb170fd2129d126d987d5032c7a31540bb6a4e93f8af15015c23ce"
+ + "1263e691903cd2c859d883c980fada91b764aef7e5a20fb22bcf5949e62c8082"
+ + "c8245bcf8686a6a39b7ef2eec49b1a047b73aeb06e3793c1d01fa24fd156",
+ new BigInteger("5a5f98ceb2f856685c51ba714d5e1db06d1e6542a8d02b9c13efeeb1f3e6613d"
+ + "8ef83e49748cb63aad268ba68c9295c507dac125f51ba75c82f6029dcc14d4ab"
+ + "16", 16),
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0002"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000401ce7a5356fd"
+ + "002ff3d9a193dd910795b56f8bd2f975367d982d27e04b4e0935425fdef6b3e1"
+ + "6fac26a898a757ddbfb01a45236a8a06ead9db3dff644ed87a7f09310000c862"
+ + "7374a123b1c0fdf7efaaee362fa7fdeb1c56bd787e81484d21a818ff49552704"
+ + "af2d2fe714a1576299ff6d3745349cdb463e8c003641c13c870391cfd360",
+ new BigInteger("c5dd96d1f0aa141f184d0a749809dc0749a0629b9b7d99d1cbe40c14204d70c7"
+ + "f63413756040a4c2a67551df6723c4b784ace44d7e35f46233c78b2c7548594b"
+ + "3d", 16),
+ "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffd"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000400d4574ad46e"
+ + "42824b7738f0ed19f0dbec65e743ed6a1798e8168546713a929c97cb8b2f3c20"
+ + "928bed9fad88319ef216e42c7a82707befead2b21000e06e6ca37709004848c1"
+ + "34a7fa6d0f8cd9aa237b84ffa02cb3bc8d84b8022153a3e01248dfc87403e8f3"
+ + "f1b70b52b7eabffd01fe1b4101fa901494a2067e2321a47e87cce45eecfd",
+ new BigInteger("01ac34343b1814a092e48f1c60de0bacced8c328246f103428ab0ce6611807e6"
+ + "90022dbc6bc558265b917dc513152cd1661b30e3b62a2cc2bf9f909e3fd51918"
+ + "de5b", 16),
+ "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffe"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a70201010342000498703a894131de3f81"
+ + "5836bdb1d5a03e59fbf50ffde6575ee690e9ebf6a32e785ad50d1eb00062a9b8"
+ + "176ba32f06f3908f82a3ddd9da10eafcac61f57a180bcb",
+ new BigInteger("17617237e4ec2629d798a81ca086c1a73494e70619dd7b77cb7360174de82107", 16),
+ "0000000000000000000000000000000000000000000000000000000000000001"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a702010103420004055f1b89b08c1c4a0f"
+ + "96ff15dd284bdad79b90636ce73c461cb6da001e19638c07490bed6a644e944a"
+ + "c3e8684c4d5cf469a3f5b039690cba52dc0dccb095e61e",
+ new BigInteger("7988ceedd4ce4f516f083261dc0dbb4d59c71b058bf00876135fb1d5e72a1cea", 16),
+ "0000000000000000000000000000000000000000000000000000000000000002"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a70201010342000424f99dbc3d8f4989f2"
+ + "43662e67de0f8d03d0f84031caa553f4a3ccc1c999de1e43530fcd456a5d83d5"
+ + "11aedc8bda7c2b18cc509cabe47e76d46501fd82ebbfae",
+ new BigInteger("844649c38c375c5f4959b129c6510e54f71a60b91d1b09a7b1a8dd0e954da186", 16),
+ "a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5376"),
+ // vectors with extreme values for the public key
+ new EcdhTestVector(
+ "secp256r1",
+ "3059301306072a8648ce3d020106082a8648ce3d030107034200040000000000"
+ + "00000000000000000000000000000000000000000000000000000066485c780e"
+ + "2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4",
+ new BigInteger("2e0a2c5159af006f28f5b51e55ce9270f17a431ebefee2d95bf2f954c3c460c5", 16),
+ "bb4b8e7b1b5d766d7e6d3de41e0ab0703cadcca4e039f310e3ed0004e2c1ba67"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b81040022036200040000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "00000000000000003cf99ef04f51a5ea630ba3f9f960dd593a14c9be39fd2bd2"
+ + "15d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e521e",
+ new BigInteger("b0a8c4804a2b9769216a51b51ece43391cf3f66c383a748d54f1c15f27bbf041"
+ + "a3b9470a6d49f8abe9e6b4db6bd7c59f", 16),
+ "6598237fdfd3f38e00c3c58a3045b9d54c510f0f5523293af1966635f2ddf963"
+ + "87b12065ad8e1a5b72618e6441c72841"),
+ new EcdhTestVector(
+ "secp384r1",
+ "3076301006072a8648ce3d020106052b8104002203620004ffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffeffffffff00000000"
+ + "00000000fffffffe732152442fb6ee5c3e6ce1d920c059bc623563814d79042b"
+ + "903ce60f1d4487fccd450a86da03f3e6ed525d02017bfdb3",
+ new BigInteger("135b5751b27de8fe0e34d452ad81c4ca90def546275c349f467aabd24e039b75"
+ + "28c473bc5732cb96921d01e6ca11739a", 16),
+ "ef5ceb524843eb0277f574b278b09f82670dbcdacbe51a646441a45ebdfa4976"
+ + "1fb3b534bfccd957edb99e9a4e329467"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b810400230381860004000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000d20ec9"
+ + "fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896fee3f8e614bc630"
+ + "54d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440ae001f4f87",
+ new BigInteger("7ca82bb7bdd0ab3805e1d25ce49f71780e93a0314f579a474d0b0f81812c8365"
+ + "bc3917eb00208a1cfdb44cdc53f112930560e86bcad563d0bd4ff951f2c41454"
+ + "f6", 16),
+ "00d6283f6a7b59628920dd3afe97a5021c79e26c71adf5c0774cedaaf5b25b92"
+ + "ed2776cfefbe95e467a15032c221064ff19b1207183f0ca0c594b6a83ca0e3f3"
+ + "2250"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b810400230381860004000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "000000000000000000000000000000000000000000000000000000010010e59b"
+ + "e93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec6"
+ + "36ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564",
+ new BigInteger("011cf3abed354498f6922af2ddc9d74b2bb829bee79cc272c7b154f16a720c29"
+ + "429bb354bb034549e33be5b84ffb6da99a0c28bb37fa44f78cce5feb871370e1"
+ + "2c93", 16),
+ "00e51b94872c9cb3831bac48e9e4cbc6b4eafdc09ce51f43d0ff118b5d429f20"
+ + "b88261dbfc9636ecf081cdcf1b1336425a39841cf1ff742bc3d5553a709cd0a7"
+ + "3a13"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000401ffffffffff"
+ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffd0010e59b"
+ + "e93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec6"
+ + "36ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564",
+ new BigInteger("011c2b1a82cd320924e757b4259e5f7c0455efe3f05d316c9705b5071fdbd59e"
+ + "db59ee938b95a67727ca01ffe5155baf5eff83ae5ec4a56770a50475b017a762"
+ + "30cf", 16),
+ "000adf30396bda59d36fc307a4f43f594806f3a46373f3e4af6516e67f99d981"
+ + "1c0496f49527895fa7738423f6429318f54afa6841cb4692e15016fe49fc7c82"
+ + "509d"),
+ new EcdhTestVector(
+ "secp521r1",
+ "30819b301006072a8648ce3d020106052b81040023038186000401ffffffffff"
+ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffe00d9254f"
+ + "df800496acb33790b103c5ee9fac12832fe546c632225b0f7fce3da4574b1a87"
+ + "9b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051d6aa505acf",
+ new BigInteger("01e1603fe7e275673aeb8b3f105f4058e073b4c37d2f0ae2bd66b189454e1b41"
+ + "c442c3f35f085eae3aa37eefffe76736440f9b3fd2e3931d468b6d90e560bc0f"
+ + "35f5", 16),
+ "0158694585e55f1289e410fdeeed82940b3029dd8207dcb4de407278a6328d5e"
+ + "b904262419f1ef2ecacb415872f0c9d64df82b1241cd780bd0abc9e26ceebadf"
+ + "44e7"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a702010103420004000000000000000000"
+ + "000000000000000000000000000000000000000000000109e0e9e8d98fb89da2"
+ + "a32b2c7618b26bb99b920f02a5e831a142e6c8673110cd",
+ new BigInteger("61c2be000b5888035bfde07d532b36d91cc347f556d87c7a01397f4cde29c6e4", 16),
+ "3db56c93e51a0b5b17a8009be010be6eecca6b7e0b587753cb8bc850869a710d"),
+ new EcdhTestVector(
+ "brainpoolp256r1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d"
+ + "1f6e5377304404207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6c"
+ + "e94a4b44f330b5d9042026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7"
+ + "e1ce6bccdc18ff8c07b60441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27"
+ + "e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745"
+ + "132ded8e545c1d54c72f046997022100a9fb57dba1eea9bc3e660a909d838d71"
+ + "8c397aa3b561a6f7901e0e82974856a702010103420004a9fb57dba1eea9bc3e"
+ + "660a909d838d726e3bf623d52620282013481d1f6e537613a0346db14d55d1bc"
+ + "c27079b68864ac32885b5bdfc3c9db6f85a35d3df4c39b",
+ new BigInteger("8527b0540fc10b025a6e0892439c59a889a52e57a0f81b4df41442869c524873", 16),
+ "a01ed9d4f5a0884db2a232dd5369d6014bfe1f2f6a6d05a757e7a078b71a1f54"),
+ };
+
+ /** Test vectors */
+ public static class EcPublicKeyTestVector {
+ final String comment;
+ final String encoded; // hexadecimal representation of the X509 encoding
+ final BigInteger p; // characteristic of the field
+ final BigInteger n; // order of the subgroup
+ final BigInteger a; // parameter a of the Weierstrass representation
+ final BigInteger b; // parameter b of the Weierstrass represnetation
+ final BigInteger gx; // x-coordinate of the generator
+ final BigInteger gy; // y-coordainat of the generator
+ final Integer h; // cofactor: may be null
+ final BigInteger pubx; // x-coordinate of the public point
+ final BigInteger puby; // y-coordinate of the public point
+
+ public EcPublicKeyTestVector(
+ String comment,
+ String encoded,
+ BigInteger p,
+ BigInteger n,
+ BigInteger a,
+ BigInteger b,
+ BigInteger gx,
+ BigInteger gy,
+ Integer h,
+ BigInteger pubx,
+ BigInteger puby) {
+ this.comment = comment;
+ this.encoded = encoded;
+ this.p = p;
+ this.n = n;
+ this.a = a;
+ this.b = b;
+ this.gx = gx;
+ this.gy = gy;
+ this.h = h;
+ this.pubx = pubx;
+ this.puby = puby;
+ }
+
+ /**
+ * Returns this key as ECPublicKeySpec or null if the key cannot be represented as
+ * ECPublicKeySpec. The later happens for example if the order of cofactor are not positive.
+ */
+ public ECPublicKeySpec getSpec() {
+ try {
+ ECFieldFp fp = new ECFieldFp(p);
+ EllipticCurve curve = new EllipticCurve(fp, a, b);
+ ECPoint g = new ECPoint(gx, gy);
+ // ECParameterSpec requires that the cofactor h is specified.
+ if (h == null) {
+ return null;
+ }
+ ECParameterSpec params = new ECParameterSpec(curve, g, n, h);
+ ECPoint pubPoint = new ECPoint(pubx, puby);
+ ECPublicKeySpec pub = new ECPublicKeySpec(pubPoint, params);
+ return pub;
+ } catch (Exception ex) {
+ System.out.println(comment + " throws " + ex.toString());
+ return null;
+ }
+ }
+
+ public X509EncodedKeySpec getX509EncodedKeySpec() {
+ return new X509EncodedKeySpec(TestUtil.hexToBytes(encoded));
+ }
+ }
+
+ public static final EcPublicKeyTestVector EC_VALID_PUBLIC_KEY =
+ new EcPublicKeyTestVector(
+ "unmodified",
+ "3059301306072a8648ce3d020106082a8648ce3d03010703420004cdeb39edd0"
+ + "3e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b84"
+ + "29598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16));
+
+ public static final EcPublicKeyTestVector[] EC_MODIFIED_PUBLIC_KEYS = {
+ // Modified keys
+ new EcPublicKeyTestVector(
+ "public point not on curve",
+ "3059301306072a8648ce3d020106082a8648ce3d03010703420004cdeb39edd0"
+ + "3e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b84"
+ + "29598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebaca",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebaca", 16)),
+ new EcPublicKeyTestVector(
+ "public point = (0,0)",
+ "3059301306072a8648ce3d020106082a8648ce3d030107034200040000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "000000000000000000000000000000000000000000000000000000",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("0"),
+ new BigInteger("0")),
+ new EcPublicKeyTestVector(
+ "order = 1",
+ "308201133081cc06072a8648ce3d02013081c0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f502010102010103420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("01", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "order = 26959946660873538060741835960514744168612397095220107664" + "918121663170",
+ "3082012f3081e806072a8648ce3d02013081dc020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5021d00ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac202010103420004cdeb39edd03e2b1a11a5e134ec"
+ + "99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49bbb85c"
+ + "3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "generator = (0,0)",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b04410400000000000000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000000000000000"
+ + "00000000000000000000000000022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc63255102010103420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "generator not on curve",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f7022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc63255102010103420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f7", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "cofactor = 2",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc63255102010203420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 2,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "cofactor = None",
+ "308201303081e906072a8648ce3d02013081dd020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc63255103420004cdeb39edd03e2b1a11a5e134"
+ + "ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49bbb8"
+ + "5c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ null,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "modified prime",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100fd091059a6893635f900e9449d63f572b2aebc4cff7b4e5e33f1b200"
+ + "e8bbc1453044042002f6efa55976c9cb06ff16bb629c0a8d4d5143b40084b1a1"
+ + "cc0e4dff17443eb704205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441040000000000000000000006597fa94b1fd90000"
+ + "000000000000000000000000021b8c7dd77f9a95627922eceefea73f028f1ec9"
+ + "5ba9b8fa95a3ad24bdf9fff414022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc63255102010103420004000000000000000000"
+ + "0006597fa94b1fd90000000000000000000000000000021b8c7dd77f9a956279"
+ + "22eceefea73f028f1ec95ba9b8fa95a3ad24bdf9fff414",
+ new BigInteger("fd091059a6893635f900e9449d63f572b2aebc4cff7b4e5e33f1b200e8bbc145", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("06597fa94b1fd9000000000000000000000000000002", 16),
+ new BigInteger("1b8c7dd77f9a95627922eceefea73f028f1ec95ba9b8fa95a3ad24bdf9fff414", 16),
+ 1,
+ new BigInteger("06597fa94b1fd9000000000000000000000000000002", 16),
+ new BigInteger("1b8c7dd77f9a95627922eceefea73f028f1ec95ba9b8fa95a3ad24bdf9fff414", 16)),
+ new EcPublicKeyTestVector(
+ "using secp224r1",
+ "304e301006072a8648ce3d020106052b81040021033a0004074f56dc2ea648ef"
+ + "89c3b72e23bbd2da36f60243e4d2067b70604af1c2165cec2f86603d60c8a611"
+ + "d5b84ba3d91dfe1a480825bcc4af3bcf",
+ new BigInteger("ffffffffffffffffffffffffffffffff000000000000000000000001", 16),
+ new BigInteger("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d", 16),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe", 16),
+ new BigInteger("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16),
+ new BigInteger("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16),
+ new BigInteger("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16),
+ 1,
+ new BigInteger("074f56dc2ea648ef89c3b72e23bbd2da36f60243e4d2067b70604af1", 16),
+ new BigInteger("c2165cec2f86603d60c8a611d5b84ba3d91dfe1a480825bcc4af3bcf", 16)),
+ new EcPublicKeyTestVector(
+ "a = 0",
+ "308201143081cd06072a8648ce3d02013081c1020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30250401000420f104880c3980129c7efa19b6b0cb04e547b8d0fc0b"
+ + "95f4946496dd4ac4a7c440044104cdeb39edd03e2b1a11a5e134ec99d5f25f21"
+ + "673d403f3ecb47bd1fa676638958ea58493b8429598c0b49bbb85c3303ddb155"
+ + "3c3b761c2caacca71606ba9ebac8022100ffffffff00000000ffffffffffffff"
+ + "ffbce6faada7179e84f3b9cac2fc63255102010103420004cdeb39edd03e2b1a"
+ + "11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c"
+ + "0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("0"),
+ new BigInteger("f104880c3980129c7efa19b6b0cb04e547b8d0fc0b95f4946496dd4ac4a7c440", 16),
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ // Invalid keys
+ new EcPublicKeyTestVector(
+ "order = -1157920892103562487626974469494075735299969552241357603"
+ + "42422259061068512044369",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f50221ff00000000ffffffff0000000000000000"
+ + "4319055258e8617b0c46353d039cdaaf02010103420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger(
+ "-115792089210356248762697446949407573529996955224135760342422259" + "061068512044369"),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "order = 0",
+ "308201123081cb06072a8648ce3d02013081bf020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5020002010103420004cdeb39edd03e2b1a11a5"
+ + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("0"),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "cofactor = -1",
+ "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc6325510201ff03420004cdeb39edd03e2b1a11"
+ + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ -1,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ new EcPublicKeyTestVector(
+ "cofactor = 0",
+ "308201323081eb06072a8648ce3d02013081df020101302c06072a8648ce3d01"
+ + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ + "bce6faada7179e84f3b9cac2fc632551020003420004cdeb39edd03e2b1a11a5"
+ + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
+ new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16),
+ new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16),
+ 0,
+ new BigInteger("cdeb39edd03e2b1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958", 16),
+ new BigInteger("ea58493b8429598c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8", 16)),
+ };
+
+ /** Checks that key agreement using ECDH works. */
+ public void testBasic() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ keyGen.initialize(ecSpec);
+ KeyPair keyPairA = keyGen.generateKeyPair();
+ KeyPair keyPairB = keyGen.generateKeyPair();
+
+ KeyAgreement kaA = KeyAgreement.getInstance("ECDH");
+ KeyAgreement kaB = KeyAgreement.getInstance("ECDH");
+ kaA.init(keyPairA.getPrivate());
+ kaB.init(keyPairB.getPrivate());
+ kaA.doPhase(keyPairB.getPublic(), true);
+ kaB.doPhase(keyPairA.getPublic(), true);
+ byte[] kAB = kaA.generateSecret();
+ byte[] kBA = kaB.generateSecret();
+ assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA));
+ }
+
+ public void testVectors() throws Exception {
+ KeyAgreement ka = KeyAgreement.getInstance("ECDH");
+ for (EcdhTestVector t : ECDH_TEST_VECTORS) {
+ try {
+ ka.init(t.getPrivateKey());
+ ka.doPhase(t.getPublicKey(), true);
+ byte[] shared = ka.generateSecret();
+ assertEquals("Curve:" + t.curvename, TestUtil.bytesToHex(shared), t.shared);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ // Skipped, because the provider does not support the curve.
+ }
+ }
+ }
+
+ public void testDecode() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey key1 = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
+ ECPublicKey key2 = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getX509EncodedKeySpec());
+ ECParameterSpec params1 = key1.getParams();
+ ECParameterSpec params2 = key1.getParams();
+ assertEquals(params1.getCofactor(), params2.getCofactor());
+ assertEquals(params1.getCurve(), params2.getCurve());
+ assertEquals(params1.getGenerator(), params2.getGenerator());
+ assertEquals(params1.getOrder(), params2.getOrder());
+ assertEquals(key1.getW(), key2.getW());
+ }
+
+ /**
+ * This test modifies the order of group in the public key. A severe bug would be an
+ * implementation that leaks information whether the private key is larger than the order given in
+ * the public key. Also a severe bug would be to reduce the private key modulo the order given in
+ * the public key parameters.
+ */
+ public void testModifiedPublic(String algorithm) throws Exception {
+ KeyAgreement ka;
+ try {
+ ka = KeyAgreement.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("testWrongOrder: " + algorithm + " not supported");
+ return;
+ }
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(EcUtil.getNistP256Params());
+ ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
+ ka.init(priv);
+ ka.doPhase(validKey, true);
+ String expected = TestUtil.bytesToHex(ka.generateSecret());
+ for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
+ try {
+ X509EncodedKeySpec spec = test.getX509EncodedKeySpec();
+ ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
+ ka.init(priv);
+ ka.doPhase(modifiedKey, true);
+ String shared = TestUtil.bytesToHex(ka.generateSecret());
+ // The implementation did not notice that the public key was modified.
+ // This is not nice, but at the moment we only fail the test if the
+ // modification was essential for computing the shared secret.
+ //
+ // BouncyCastle v.1.53 fails this test, for ECDHC with modified order.
+ // This implementation reduces the product s*h modulo the order given
+ // in the public key. An attacker who can modify the order of the public key
+ // and who can learn whether such a modification changes the shared secret is
+ // able to learn the private key with a simple binary search.
+ assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
+ } catch (GeneralSecurityException ex) {
+ // OK, since the public keys have been modified.
+ System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
+ }
+ }
+ }
+
+ /**
+ * This is a similar test as testModifiedPublic. However, this test uses test vectors
+ * ECPublicKeySpec
+ */
+ public void testModifiedPublicSpec(String algorithm) throws Exception {
+ KeyAgreement ka;
+ try {
+ ka = KeyAgreement.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("testWrongOrder: " + algorithm + " not supported");
+ return;
+ }
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ keyGen.initialize(EcUtil.getNistP256Params());
+ ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
+ ka.init(priv);
+ ka.doPhase(validKey, true);
+ String expected = TestUtil.bytesToHex(ka.generateSecret());
+ for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
+ ECPublicKeySpec spec = test.getSpec();
+ if (spec == null) {
+ // The constructor of EcPublicKeySpec performs some very minor validity checks.
+ // spec == null if one of these validity checks fails. Of course such a failure is OK.
+ continue;
+ }
+ try {
+ ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
+ ka.init(priv);
+ ka.doPhase(modifiedKey, true);
+ String shared = TestUtil.bytesToHex(ka.generateSecret());
+ // The implementation did not notice that the public key was modified.
+ // This is not nice, but at the moment we only fail the test if the
+ // modification was essential for computing the shared secret.
+ //
+ // BouncyCastle v.1.53 fails this test, for ECDHC with modified order.
+ // This implementation reduces the product s*h modulo the order given
+ // in the public key. An attacker who can modify the order of the public key
+ // and who can learn whether such a modification changes the shared secret is
+ // able to learn the private key with a simple binary search.
+ assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
+ } catch (GeneralSecurityException ex) {
+ // OK, since the public keys have been modified.
+ System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
+ }
+ }
+ }
+
+ public void testDistinctCurves(String algorithm, ECPrivateKey priv, ECPublicKey pub)
+ throws Exception {
+ KeyAgreement kaA;
+ try {
+ kaA = KeyAgreement.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("Algorithm not supported: " + algorithm);
+ return;
+ }
+ byte[] shared;
+ try {
+ kaA.init(priv);
+ kaA.doPhase(pub, true);
+ shared = kaA.generateSecret();
+ } catch (InvalidKeyException ex) {
+ // This is expected.
+ return;
+ }
+ // Printing some information to determine what might have gone wrong:
+ // E.g., if the generated secret is the same as the x-coordinate of the public key
+ // then it is likely that the ECDH computation was using a fake group with small order.
+ // Such a situation is probably exploitable.
+ // This probably is exploitable. If the curve of the private key was used for the ECDH
+ // then the generated secret and the x-coordinate of the public key are likely
+ // distinct.
+ EllipticCurve pubCurve = pub.getParams().getCurve();
+ EllipticCurve privCurve = priv.getParams().getCurve();
+ ECPoint pubW = pub.getW();
+ System.out.println("testDistinctCurves: algorithm=" + algorithm);
+ System.out.println(
+ "Private key: a="
+ + privCurve.getA()
+ + " b="
+ + privCurve.getB()
+ + " p"
+ + EcUtil.getModulus(privCurve));
+ System.out.println(" s =" + priv.getS());
+ System.out.println(
+ "Public key: a="
+ + pubCurve.getA()
+ + " b="
+ + pubCurve.getB()
+ + " p"
+ + EcUtil.getModulus(pubCurve));
+ System.out.println(" w = (" + pubW.getAffineX() + ", " + pubW.getAffineY() + ")");
+ System.out.println(
+ " = ("
+ + pubW.getAffineX().toString(16)
+ + ", "
+ + pubW.getAffineY().toString(16)
+ + ")");
+ System.out.println("generated shared secret:" + TestUtil.bytesToHex(shared));
+ fail("Generated secret with distinct Curves using " + algorithm);
+ }
+
+ /**
+ * This test tries to catch implementations that verify that the point of the public key is on the
+ * curve defined by the private key, but fails to verify that public key and private key use the
+ * same curve.
+ *
+ * <p>Bouncycastle v.1.53 fails this test. I.e. this version only checks that the shared secret is
+ * on the curve, but does not check whether the two curves are the same. Currently the test fails
+ * with a NullPointerException (possibly because of unexpected points at infinity) and it is
+ * unclear if the bug is exploitable.
+ */
+ // TODO(bleichen): This can be merged with testModifiedPublic once this is fixed.
+ public void testDistinctCurvesSmallSubGroup() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecSpec256 = new ECGenParameterSpec("secp256r1");
+ keyGen.initialize(ecSpec256);
+ ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ // Get public key for a group of order 3. I.e., (W, -W, infinity) where W is the public key
+ // point. Since W ,-W and infinity are points on secp256r1, implementations fail if they only
+ // check whether points are on the curve but fail to compare the parameters of the curve.
+ ECPublicKeySpec weak = EcUtil.getWeakPublicKey(EcUtil.getNistP256Params());
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey weakPub;
+ try {
+ weakPub = (ECPublicKey) kf.generatePublic(weak);
+ } catch (GeneralSecurityException ex) {
+ // The provider does not support non-standard curves or did a validity check.
+ // Both would be correct.
+ System.out.println("Skipping testDistinctCurvesSmallSubGroup: can't forge weak public key.");
+ return;
+ }
+ for (String algorithm : ECDH_VARIANTS) {
+ testDistinctCurves(algorithm, priv, weakPub);
+ }
+ }
+
+ /**
+ * This test modifies the order of group in the public key. A severe bug would be an
+ * implementation that leaks information whether the private key is larger than the order given in
+ * the public key. Also a severe bug would be to reduce the private key modulo the order given in
+ * the public key parameters.
+ */
+ // TODO(bleichen): This can be merged with testModifiedPublic once this is fixed.
+ public void testWrongOrder(String algorithm, ECParameterSpec spec) throws Exception {
+ KeyAgreement ka;
+ try {
+ ka = KeyAgreement.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("testWrongOrder: " + algorithm + " not supported");
+ return;
+ }
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ ECPrivateKey priv;
+ ECPublicKey pub;
+ try {
+ keyGen.initialize(spec);
+ priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
+ pub = (ECPublicKey) keyGen.generateKeyPair().getPublic();
+ } catch (GeneralSecurityException ex) {
+ // This is OK, since not all provider support Brainpool curves
+ System.out.println("testWrongOrder: could not generate keys for curve");
+ return;
+ }
+ // Get the shared secret for the unmodified keys.
+ ka.init(priv);
+ ka.doPhase(pub, true);
+ byte[] shared = ka.generateSecret();
+ // Generate a modified public key.
+ ECParameterSpec modifiedParams =
+ new ECParameterSpec(
+ spec.getCurve(), spec.getGenerator(), spec.getOrder().shiftRight(16), 1);
+ ECPublicKeySpec modifiedPubSpec = new ECPublicKeySpec(pub.getW(), modifiedParams);
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey modifiedPub;
+ try {
+ modifiedPub = (ECPublicKey) kf.generatePublic(modifiedPubSpec);
+ } catch (GeneralSecurityException ex) {
+ // The provider does not support non-standard curves or did a validity check.
+ // Both would be correct.
+ System.out.println("testWrongOrder: can't modify order.");
+ return;
+ }
+ byte[] shared2;
+ try {
+ ka.init(priv);
+ ka.doPhase(modifiedPub, true);
+ shared2 = ka.generateSecret();
+ } catch (GeneralSecurityException ex) {
+ // This is the expected behavior
+ System.out.println("testWrongOrder:" + ex.toString());
+ return;
+ }
+ // TODO(bleichen): Getting here is already a bug and we might flag this later.
+ // At the moment we are only interested in really bad behavior of a library, that potentially
+ // leaks the secret key. This is the case when the shared secrets are different, since this
+ // suggests that the implementation reduces the multiplier modulo the given order of the curve
+ // or some other behaviour that is dependent on the private key.
+ // An attacker who can check whether a DH computation was done correctly or incorrectly because
+ // of modular reduction, can determine the private key, either by a binary search or by trying
+ // to guess the private key modulo some small "order".
+ // BouncyCastle v.1.53 fails this test, and leaks the private key.
+ System.out.println(
+ "Generated shared secret with a modified order:"
+ + algorithm
+ + "\n"
+ + "expected:"
+ + TestUtil.bytesToHex(shared)
+ + " computed:"
+ + TestUtil.bytesToHex(shared2));
+ assertEquals(
+ "Algorithm:" + algorithm, TestUtil.bytesToHex(shared), TestUtil.bytesToHex(shared2));
+ }
+
+ public void testWrongOrderEcdh() throws Exception {
+ testWrongOrder("ECDH", EcUtil.getNistP256Params());
+ testWrongOrder("ECDH", EcUtil.getBrainpoolP256r1Params());
+ }
+
+ public void testWrongOrderEcdhc() throws Exception {
+ testWrongOrder("ECDHC", EcUtil.getNistP256Params());
+ testWrongOrder("ECDHC", EcUtil.getBrainpoolP256r1Params());
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/EcdsaTest.java b/java/com/google/security/wycheproof/testcases/EcdsaTest.java
new file mode 100644
index 0000000..37cfa82
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/EcdsaTest.java
@@ -0,0 +1,462 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+import com.google.security.wycheproof.WycheproofRunner.SlowTest;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+/**
+ * Tests ECDSA against invalid signatures.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// Tested providers:
+// SunEC: accepts a few alternative encodings and throws run time exceptions.
+// The implementation does not protect against timing attacks.
+// BC: accepts alternative encoding, and additional arguments
+// AndroidOpenSSL: OK
+// TODO(bleichen):
+// - CVE-2015-2730: Firefox failed to handle some signatures correctly because of incorrect
+// point multiplication. (I don't have enough information here.)
+public class EcdsaTest extends TestCase {
+ // ECDSA-Key1
+ static final String MESSAGE = "Hello";
+ static final String CURVE = "secp256r1";
+ static final BigInteger PubX =
+ new BigInteger(
+ "3390396496586153202365024500890309020181905168626402195853036609" + "0984128098564");
+ static final BigInteger PubY =
+ new BigInteger(
+ "1135421298983937257390683162600855221890652900790509030911087400" + "65052129055287");
+
+ // Valid signatures for MESSAGE
+ static final String[] VALID_SIGNATURES = {
+ "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ + "1b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285"
+ + "cd59f43260ecce",
+ };
+
+ /**
+ * Test vectors with invalid signatures. The motivation for these test vectors are previously
+ * broken implementations. - The implementation of DSA in gpg4browsers accepted signatures with
+ * r=1 and s=q as valid. Similar bugs in ECDSA are thinkable, hence the test vectors contain a
+ * number of tests with edge case integers. - CVE-2013-2944: strongSwan 5.0.4 accepts invalid
+ * ECDSA signatures when openssl is used. (Not sure if the following interpretation is correct,
+ * because of missing details). OpenSSLs error codes are easy to misinterpret. For many functions
+ * the result can be 0 (verification failed), 1 (verification succeded) or -1 (invalid format). A
+ * simple if (result) { ... } will be incorrect in such situations. The test vectors below contain
+ * incorrectly encoded signatures. - careless ASN parsing. For example SunEC throws various run
+ * time exceptions when the ASN encoding is broken. NOTE(bleichen): The following test vectors
+ * were generated with some python code. New test vectors should best be done by extending this
+ * code.
+ */
+ static final String[] INVALID_SIGNATURES = {
+ // missing argument
+ "30220220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f4" + "3260ecce",
+ "3023022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f",
+ "",
+ // empty
+ "302402000220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285cd" + "59f43260ecce",
+ "3025022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f0200",
+ "3000",
+ // integer overflows
+ "304a0285010000002100b7babae9332b54b8a3a05b7004579821a887a1b21465"
+ + "f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ + "06a6e76285cd59f43260ecce",
+ "304e028901000000000000002100b7babae9332b54b8a3a05b7004579821a887"
+ + "a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f"
+ + "94e418c106a6e76285cd59f43260ecce",
+ "304a022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ + "1b39fd2c3f02850100000020747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ + "06a6e76285cd59f43260ecce",
+ "304e022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ + "1b39fd2c3f0289010000000000000020747291dd2f3f44af7ace68ea33431d6f"
+ + "94e418c106a6e76285cd59f43260ecce",
+ "30850100000045022100b7babae9332b54b8a3a05b7004579821a887a1b21465"
+ + "f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ + "06a6e76285cd59f43260ecce",
+ "3089010000000000000045022100b7babae9332b54b8a3a05b7004579821a887"
+ + "a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f"
+ + "94e418c106a6e76285cd59f43260ecce",
+ // infinity
+ "30250901800220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285" + "cd59f43260ecce",
+ "3026022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f090180",
+ // Signatures with special case values for r and s (such as 0 and 1).
+ // Such values often uncover implementation errors.
+ "300402000200",
+ "30050200020101",
+ "300502000201ff",
+ "30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632551",
+ "30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632550",
+ "30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632552",
+ "30250200022100ffffffff00000001000000000000000000000000ffffffffff" + "ffffffffffffff",
+ "30250200022100ffffffff000000010000000000000000000000010000000000" + "00000000000000",
+ "30070200090380fe01",
+ "30050201010200",
+ "3006020101020101",
+ "30060201010201ff",
+ "3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632551",
+ "3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632550",
+ "3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632552",
+ "3026020101022100ffffffff00000001000000000000000000000000ffffffff" + "ffffffffffffffff",
+ "3026020101022100ffffffff0000000100000000000000000000000100000000" + "0000000000000000",
+ "3008020101090380fe01",
+ "30050201ff0200",
+ "30060201ff020101",
+ "30060201ff0201ff",
+ "30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632551",
+ "30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632550",
+ "30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632552",
+ "30260201ff022100ffffffff00000001000000000000000000000000ffffffff" + "ffffffffffffffff",
+ "30260201ff022100ffffffff0000000100000000000000000000000100000000" + "0000000000000000",
+ "30080201ff090380fe01",
+ "3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325510200",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632551020101",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325510201ff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632551",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632550",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632552",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632551022100ffffffff00000001000000000000000000000000ffffffff"
+ + "ffffffffffffffff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632551022100ffffffff0000000100000000000000000000000100000000"
+ + "0000000000000000",
+ "3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632551090380fe01",
+ "3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325500200",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632550020101",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325500201ff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632551",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632550",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632552",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632550022100ffffffff00000001000000000000000000000000ffffffff"
+ + "ffffffffffffffff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632550022100ffffffff0000000100000000000000000000000100000000"
+ + "0000000000000000",
+ "3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632550090380fe01",
+ "3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325520200",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632552020101",
+ "3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325520201ff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632551",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632550",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632552",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632552022100ffffffff00000001000000000000000000000000ffffffff"
+ + "ffffffffffffffff",
+ "3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ + "c2fc632552022100ffffffff0000000100000000000000000000000100000000"
+ + "0000000000000000",
+ "3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632552090380fe01",
+ "3025022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff0200",
+ "3026022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff020101",
+ "3026022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff0201ff",
+ "3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ + "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632551",
+ "3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ + "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632550",
+ "3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ + "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632552",
+ "3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ + "ffffffffff022100ffffffff00000001000000000000000000000000ffffffff"
+ + "ffffffffffffffff",
+ "3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ + "ffffffffff022100ffffffff0000000100000000000000000000000100000000"
+ + "0000000000000000",
+ "3028022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff090380fe01",
+ "3025022100ffffffff0000000100000000000000000000000100000000000000" + "00000000000200",
+ "3026022100ffffffff0000000100000000000000000000000100000000000000" + "0000000000020101",
+ "3026022100ffffffff0000000100000000000000000000000100000000000000" + "00000000000201ff",
+ "3046022100ffffffff0000000100000000000000000000000100000000000000"
+ + "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632551",
+ "3046022100ffffffff0000000100000000000000000000000100000000000000"
+ + "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632550",
+ "3046022100ffffffff0000000100000000000000000000000100000000000000"
+ + "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ + "f3b9cac2fc632552",
+ "3046022100ffffffff0000000100000000000000000000000100000000000000"
+ + "0000000000022100ffffffff00000001000000000000000000000000ffffffff"
+ + "ffffffffffffffff",
+ "3046022100ffffffff0000000100000000000000000000000100000000000000"
+ + "0000000000022100ffffffff0000000100000000000000000000000100000000"
+ + "0000000000000000",
+ "3028022100ffffffff0000000100000000000000000000000100000000000000" + "0000000000090380fe01",
+ };
+
+ /**
+ * Determines the Hash name from the ECDSA algorithm. There is a small inconsistency in the naming
+ * of algorithms. The Oracle standard use no hyphen in SHA256WithECDSA but uses a hyphen in the
+ * message digest, i.e., SHA-256.
+ */
+ public String getHashAlgorithm(String ecdsaAlgorithm) {
+ ecdsaAlgorithm = ecdsaAlgorithm.toUpperCase();
+ int idx = ecdsaAlgorithm.indexOf("WITH");
+ if (idx > 0) {
+ if (ecdsaAlgorithm.startsWith("SHA")) {
+ return "SHA-" + ecdsaAlgorithm.substring(3, idx);
+ } else {
+ return ecdsaAlgorithm.substring(0, idx);
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Extract the integer r from an ECDSA signature. This method implicitely assumes that the ECDSA
+ * signature is DER encoded. and that the order of the curve is smaller than 2^1024.
+ */
+ BigInteger extractR(byte[] signature) throws Exception {
+ int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
+ int lengthR = signature[startR + 1];
+ return new BigInteger(Arrays.copyOfRange(signature, startR + 2, startR + 2 + lengthR));
+ }
+
+ BigInteger extractS(byte[] signature) throws Exception {
+ int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
+ int lengthR = signature[startR + 1];
+ int startS = startR + 2 + lengthR;
+ int lengthS = signature[startS + 1];
+ return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
+ }
+
+ /** Extract the k that was used to sign the signature. */
+ BigInteger extractK(byte[] signature, BigInteger h, ECPrivateKey priv) throws Exception {
+ BigInteger x = priv.getS();
+ BigInteger n = priv.getParams().getOrder();
+ BigInteger r = extractR(signature);
+ BigInteger s = extractS(signature);
+ BigInteger k = x.multiply(r).add(h).multiply(s.modInverse(n)).mod(n);
+ return k;
+ }
+
+ public ECPublicKeySpec publicKey1() throws Exception {
+ ECParameterSpec params = EcUtil.getNistP256Params();
+ ECPoint w = new ECPoint(PubX, PubY);
+ return new ECPublicKeySpec(w, params);
+ }
+
+ public void testVectors(
+ String[] signatures,
+ ECPublicKeySpec pubSpec,
+ String message,
+ String algorithm,
+ String signatureType,
+ boolean isValid)
+ throws Exception {
+ byte[] messageBytes = message.getBytes("UTF-8");
+ Signature verifier = Signature.getInstance(algorithm);
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPublicKey pub = (ECPublicKey) kf.generatePublic(pubSpec);
+ int errors = 0;
+ for (String signature : signatures) {
+ byte[] signatureBytes = TestUtil.hexToBytes(signature);
+ verifier.initVerify(pub);
+ verifier.update(messageBytes);
+ boolean verified = false;
+ try {
+ verified = verifier.verify(signatureBytes);
+ } catch (SignatureException ex) {
+ // verify can throw SignatureExceptions if the signature is malformed.
+ // We don't flag these cases and simply consider the signature as invalid.
+ verified = false;
+ }
+ //
+ if (isValid && !verified) {
+ System.out.println(signatureType + " was not verified:" + signature);
+ errors++;
+ } else if (!isValid && verified) {
+ System.out.println(signatureType + " was verified:" + signature);
+ errors++;
+ }
+ }
+ assertEquals(0, errors);
+ }
+
+ public void testValidSignatures() throws Exception {
+ testVectors(
+ VALID_SIGNATURES, publicKey1(), "Hello", "SHA256WithECDSA", "Valid ECDSA signature", true);
+ }
+
+ public void testInvalidSignatures() throws Exception {
+ testVectors(
+ INVALID_SIGNATURES,
+ publicKey1(),
+ "Hello",
+ "SHA256WithECDSA",
+ "Invalid ECDSA signature",
+ false);
+ }
+
+ /**
+ * This test checks the basic functionality of ECDSA. It can also be used to generate simple test
+ * vectors.
+ */
+ public void testBasic() throws Exception {
+ String algorithm = "SHA256WithECDSA";
+ String hashAlgorithm = "SHA-256";
+ String message = "Hello";
+ String curve = "secp256r1";
+
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ keyGen.initialize(ecSpec);
+ KeyPair keyPair = keyGen.generateKeyPair();
+ ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
+ ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
+
+ byte[] messageBytes = message.getBytes("UTF-8");
+ Signature signer = Signature.getInstance(algorithm);
+ Signature verifier = Signature.getInstance(algorithm);
+ signer.initSign(priv);
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ verifier.initVerify(pub);
+ verifier.update(messageBytes);
+ assertTrue(verifier.verify(signature));
+
+ // Extract some parameters.
+ byte[] rawHash = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+ ECParameterSpec params = priv.getParams();
+
+ // Print keys and signature, so that it can be used to generate new test vectors.
+ System.out.println("Message:" + message);
+ System.out.println("Hash:" + TestUtil.bytesToHex(rawHash));
+ System.out.println("Curve:" + curve);
+ System.out.println("Order:" + params.getOrder().toString());
+ System.out.println("Private key:");
+ System.out.println("S:" + priv.getS().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
+ System.out.println("Public key:");
+ ECPoint w = pub.getW();
+ System.out.println("X:" + w.getAffineX().toString());
+ System.out.println("Y:" + w.getAffineY().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
+ System.out.println("Signature:" + TestUtil.bytesToHex(signature));
+ System.out.println("r:" + extractR(signature).toString());
+ System.out.println("s:" + extractS(signature).toString());
+ }
+
+ /** Checks whether the one time key k in ECDSA is biased. */
+ public void testBias(String algorithm, String curve, ECParameterSpec ecParams) throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
+ try {
+ keyGen.initialize(ecParams);
+ } catch (InvalidAlgorithmParameterException ex) {
+ System.out.println("This provider does not support curve:" + curve);
+ return;
+ }
+ KeyPair keyPair = keyGen.generateKeyPair();
+ ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
+ // If we throw a fair coin tests times then the probability that
+ // either heads or tails appears less than mincount is less than 2^{-32}.
+ // Therefore the test below is not expected to fail unless the generation
+ // of the one time keys is indeed biased.
+ final int tests = 1024;
+ final int mincount = 410;
+
+ String hashAlgorithm = getHashAlgorithm(algorithm);
+ String message = "Hello";
+ byte[] messageBytes = message.getBytes("UTF-8");
+ byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+
+ // TODO(bleichen): Truncate the digest if the digest size is larger than the
+ // curve size.
+ BigInteger h = new BigInteger(1, digest);
+ BigInteger q = priv.getParams().getOrder();
+ BigInteger qHalf = q.shiftRight(1);
+
+ Signature signer = Signature.getInstance(algorithm);
+ signer.initSign(priv);
+ int countLsb = 0; // count the number of k's with msb set
+ int countMsb = 0; // count the number of k's with lsb set
+ for (int i = 0; i < tests; i++) {
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ BigInteger k = extractK(signature, h, priv);
+ if (k.testBit(0)) {
+ countLsb++;
+ }
+ if (k.compareTo(qHalf) == 1) {
+ countMsb++;
+ }
+ }
+ System.out.println(
+ signer.getProvider().getName()
+ + " curve:"
+ + curve
+ + " countLsb:"
+ + countLsb
+ + " countMsb:"
+ + countMsb);
+ if (countLsb < mincount || countLsb > tests - mincount) {
+ fail("Bias detected in the least significant bit of k:" + countLsb);
+ }
+ if (countMsb < mincount || countMsb > tests - mincount) {
+ fail("Bias detected in the most significant bit of k:" + countMsb);
+ }
+ }
+
+ @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.CONSCRYPT, ProviderType.OPENJDK,
+ ProviderType.SPONGY_CASTLE})
+ public void testBiasAll() throws Exception {
+ testBias("SHA256WithECDSA", "secp256r1", EcUtil.getNistP256Params());
+ testBias("SHA224WithECDSA", "secp224r1", EcUtil.getNistP224Params());
+ testBias("SHA384WithECDSA", "secp384r1", EcUtil.getNistP384Params());
+ testBias("SHA512WithECDSA", "secp521r1", EcUtil.getNistP521Params());
+ testBias("SHA256WithECDSA", "brainpoolP256r1", EcUtil.getBrainpoolP256r1Params());
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/EciesTest.java b/java/com/google/security/wycheproof/testcases/EciesTest.java
new file mode 100644
index 0000000..534a224
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/EciesTest.java
@@ -0,0 +1,347 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.nio.ByteBuffer;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.HashSet;
+import javax.crypto.Cipher;
+import junit.framework.TestCase;
+
+/**
+ * Testing ECIES.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// Tested providers:
+// BouncyCastle v 1.52: IESCipher is amazingly buggy, both from a crypto
+// viewpoint and from an engineering viewpoint. It uses encryption modes that are completely
+// inapproriate for ECIES or DHIES (i.e. ECB), the CBC implementation distinguishes between
+// padding and MAC failures allowing adaptive chosen-ciphertext attacks. The implementation
+// allows to specify paddings, but ignores them, encryption using ByteBuffers doesn't even work
+// without exceptions, indicating that this hasn't even tested.
+//
+// <p>TODO(bleichen):
+// - compressed points,
+// - maybe again CipherInputStream, CipherOutputStream,
+// - BouncyCastle has a KeyPairGenerator for ECIES. Is this one different from EC?
+public class EciesTest extends TestCase {
+
+ int expectedCiphertextLength(String algorithm, int coordinateSize, int messageLength)
+ throws Exception {
+ switch (algorithm.toUpperCase()) {
+ case "ECIESWITHAES-CBC":
+ // Uses the encoding
+ // 0x04 || coordinate x || coordinate y || PKCS5 padded ciphertext || 20-byte HMAC-digest.
+ return 1 + (2 * coordinateSize) + (messageLength - messageLength % 16 + 16) + 20;
+ default:
+ fail("Not implemented");
+ }
+ return -1;
+ }
+
+ /**
+ * Check that key agreement using ECIES works. This example does not specify an IESParametersSpec.
+ * BouncyCastle v.1.52 uses the following algorithms: KDF2 with SHA1 for the key derivation
+ * AES-CBC with PKCS #5 padding. HMAC-SHA1 with a 20 byte digest. The AES and the HMAC key are
+ * both 128 bits.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testEciesBasic() throws Exception {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ PrivateKey priv = keyPair.getPrivate();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = "Hello".getBytes("UTF-8");
+ Cipher ecies = Cipher.getInstance("ECIESwithAES-CBC");
+ ecies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = ecies.doFinal(message);
+ System.out.println("testEciesBasic:" + TestUtil.bytesToHex(ciphertext));
+ ecies.init(Cipher.DECRYPT_MODE, priv);
+ byte[] decrypted = ecies.doFinal(ciphertext);
+ assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
+ }
+
+ /**
+ * ECIES does not allow encryption modes and paddings. If this test fails then we should add
+ * additional tests covering the new algorithms.
+ */
+ // TODO(bleichen): This test describes BouncyCastles behaviour, but not necessarily what we
+ // expect.
+ @SuppressWarnings("InsecureCipherMode")
+ public void testInvalidNames() throws Exception {
+ String[] invalidNames =
+ new String[] {
+ "ECIESWITHAES/CBC/PKCS5PADDING",
+ "ECIESWITHAES/CBC/PKCS7PADDING",
+ "ECIESWITHAES/ECB/NOPADDING",
+ "ECIESWITHAES/CTR/NOPADDING",
+ };
+ for (String algorithm : invalidNames) {
+ try {
+ Cipher.getInstance(algorithm);
+ fail("unexpected algorithm:" + algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ // this is expected
+ }
+ }
+ }
+
+ /** Here are a few names that BouncyCastle accepts. */
+ // TODO(bleichen): This test describes BouncyCastles behaviour, but not necessarily what we
+ // expect.
+ @SuppressWarnings("InsecureCipherMode")
+ public void testValidNames() throws Exception {
+ String[] invalidNames =
+ new String[] {
+ "ECIESWITHAES/DHAES/NOPADDING",
+ "ECIES/DHAES/PKCS7PADDING",
+ "ECIESWITHDESEDE/DHAES/NOPADDING",
+ "ECIESWITHAES-CBC/NONE/NOPADDING",
+ };
+ for (String algorithm : invalidNames) {
+ Cipher.getInstance(algorithm);
+ }
+ }
+
+ /**
+ * BouncyCastle has a key generation algorithm "ECIES". This test checks that the result are
+ * ECKeys in both cases.
+ */
+ public void testKeyGeneration() throws Exception {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("ECIES");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
+ ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
+ }
+
+ /**
+ * Check the length of the ciphertext. TODO(bleichen): This is more an explanation what is going
+ * on than a test. Maybe remove this later.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testCiphertextLength() throws Exception {
+ String algorithm = "ECIESwithAES-CBC";
+ final int messageLength = 40;
+ final int coordinateSize = 32;
+ byte[] message = new byte[messageLength];
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ PublicKey pub = keyPair.getPublic();
+ Cipher ecies = Cipher.getInstance(algorithm);
+ ecies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = ecies.doFinal(message);
+ assertEquals(
+ expectedCiphertextLength(algorithm, coordinateSize, messageLength), ciphertext.length);
+ }
+
+ // Tries to decrypt ciphertexts where the symmetric part has been
+ // randomized. Distinguishable exceptions mean that a padding attack
+ // may be possible.
+ @SuppressWarnings("InsecureCipherMode")
+ public void testExceptions(String algorithm) throws Exception {
+ Cipher ecies;
+ try {
+ ecies = Cipher.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ // Allowing to skip the algorithm
+ System.out.println("No implementation for:" + algorithm);
+ return;
+ }
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ final int kemSize = 65;
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ PrivateKey priv = keyPair.getPrivate();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = new byte[40];
+ ecies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = ecies.doFinal(message);
+ System.out.println(TestUtil.bytesToHex(ciphertext));
+ ecies.init(Cipher.DECRYPT_MODE, priv);
+ HashSet<String> exceptions = new HashSet<String>();
+ for (int byteNr = kemSize; byteNr < ciphertext.length; byteNr++) {
+ for (int bit = 0; bit < 8; bit++) {
+ byte[] corrupt = Arrays.copyOf(ciphertext, ciphertext.length);
+ corrupt[byteNr] ^= (byte) (1 << bit);
+ ecies.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ try {
+ ecies.doFinal(corrupt);
+ fail("Decrypted:" + TestUtil.bytesToHex(corrupt));
+ } catch (Exception ex) {
+ String exception = ex.toString();
+ if (exceptions.add(exception)) {
+ System.out.println(algorithm + ":" + exception);
+ }
+ }
+ }
+ }
+ assertEquals(1, exceptions.size());
+ }
+
+ public void testEciesCorruptDefault() throws Exception {
+ testExceptions("ECIES");
+ }
+
+ @SuppressWarnings("InsecureCipherMode")
+ public void testModifyPoint() throws Exception {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ PrivateKey priv = keyPair.getPrivate();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = "This is a long text since we need 32 bytes.".getBytes("UTF-8");
+ Cipher ecies = Cipher.getInstance("ECIESwithAES-CBC");
+ ecies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = ecies.doFinal(message);
+ ciphertext[2] ^= (byte) 1;
+ ecies.init(Cipher.DECRYPT_MODE, priv);
+ try {
+ ecies.doFinal(ciphertext);
+ fail("This should not work");
+ } catch (java.lang.IllegalArgumentException ex) {
+ // This is what BouncyCastle throws when the points are not on the curve.
+ // Maybe GeneralSecurityException would be better.
+ }
+ }
+
+ /**
+ * This test tries to detect ECIES implementations using ECB. This is insecure and also violates
+ * the claims of ECIES, since ECIES is secure agains adaptive chosen-ciphertext attacks.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testNotEcb(String algorithm) throws Exception {
+ Cipher ecies;
+ try {
+ ecies = Cipher.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException ex) {
+ // This test is called with short algorithm names such as just "ECIES".
+ // Requiring full names is typically a good practice. Hence it is OK
+ // to not assigning default algorithms.
+ System.out.println("No implementation for:" + algorithm);
+ return;
+ }
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ PublicKey pub = keyPair.getPublic();
+ byte[] message = new byte[512];
+ ecies.init(Cipher.ENCRYPT_MODE, pub);
+ byte[] ciphertext = ecies.doFinal(message);
+ String block1 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, 241, 257));
+ String block2 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, 257, 273));
+ assertTrue("Ciphertext repeats:" + TestUtil.bytesToHex(ciphertext), !block1.equals(block2));
+ }
+
+ public void testDefaultEcies() throws Exception {
+ testNotEcb("ECIES");
+ }
+
+ /**
+ * Tests whether algorithmA is an alias of algorithmB by encrypting with algorithmA and decrypting
+ * with algorithmB.
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testIsAlias(String algorithmA, String algorithmB) throws Exception {
+ Cipher eciesA;
+ Cipher eciesB;
+ // Allowing tests to be skipped, because we don't want to encourage abbreviations.
+ try {
+ eciesA = Cipher.getInstance(algorithmA);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("Skipping because of:" + ex.toString());
+ return;
+ }
+ try {
+ eciesB = Cipher.getInstance(algorithmB);
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("Skipping because of:" + ex.toString());
+ return;
+ }
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ byte[] message = "Hello".getBytes("UTF-8");
+ eciesA.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
+ byte[] ciphertext = eciesA.doFinal(message);
+ eciesB.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ byte[] decrypted = eciesB.doFinal(ciphertext);
+ assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
+ }
+
+ /** Tests whether two distinct algorithm names implement the same cipher */
+ public void testAlias() throws Exception {
+ testIsAlias("ECIESWITHAES-CBC", "ECIESWithAES-CBC");
+ testIsAlias("ECIESWITHAES", "ECIESWithAES");
+ // BouncyCastle v 1.52 ignores mode and padding and considers the following
+ // names as equivalent:
+ // testIsAlias("ECIES/DHAES/PKCS7PADDING", "ECIES");
+ testIsAlias("ECIESWITHAES-CBC/NONE/PKCS7PADDING", "ECIESWITHAES-CBC/NONE/NOPADDING");
+ }
+
+ /**
+ * Cipher.doFinal(ByteBuffer, ByteBuffer) should be copy-safe according to
+ * https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
+ *
+ * <p>This test tries to verify this.
+ */
+ /* TODO(bleichen): There's no point to run this test as long as not even the previous basic
+ test fails.
+ public void testByteBufferAlias() throws Exception {
+ byte[] message = "Hello".getBytes("UTF-8");
+ String algorithm = "ECIESWithAES-CBC";
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
+ KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
+ kf.initialize(ecSpec);
+ KeyPair keyPair = kf.generateKeyPair();
+ Cipher ecies = Cipher.getInstance(algorithm);
+
+ int ciphertextLength = expectedCiphertextLength(algorithm, 32, message.length);
+ byte[] backingArray = new byte[ciphertextLength];
+ ByteBuffer ptBuffer = ByteBuffer.wrap(backingArray);
+ ptBuffer.put(message);
+ ptBuffer.flip();
+
+ ecies.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
+ ByteBuffer ctBuffer = ByteBuffer.wrap(backingArray);
+ ecies.doFinal(ptBuffer, ctBuffer);
+ ctBuffer.flip();
+
+ ecies.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ byte[] decrypted = ecies.doFinal(backingArray, 0, ctBuffer.remaining());
+ assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
+ }
+ */
+}
diff --git a/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java b/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java
new file mode 100644
index 0000000..79a9d5c
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/RsaEncryptionTest.java
@@ -0,0 +1,138 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import junit.framework.TestCase;
+
+/**
+ * RSA encryption tests
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// TODO(bleichen): test vectors check special cases:
+// - ciphertext too long
+// - plaintext too long
+// - ciphertext 0
+// - ciphertext == modulus timing attacks
+public class RsaEncryptionTest extends TestCase {
+
+ /**
+ * Providers that implement RSA with PKCS1Padding but not OAEP are outdated and should be avoided
+ * even if RSA is currently not used in a project. Such providers promote using an insecure
+ * cipher. There is a great danger that PKCS1Padding is used as a temporary workaround, but later
+ * stays in the project for much longer than necessary.
+ */
+ public void testOutdatedProvider() throws Exception {
+ try {
+ Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ try {
+ Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
+ } catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
+ fail("Provider " + c.getProvider().getName() + " is outdated and should not be used.");
+ }
+ } catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
+ System.out.println("RSA/ECB/PKCS1Padding is not implemented");
+ }
+ }
+
+ /**
+ * Tries decrypting random messages with a given algorithm. Counts the number of distinct error
+ * messages and expects this number to be 1.
+ *
+ * <p><b>References:</b>
+ *
+ * <ul>
+ * <li>Bleichenbacher, "Chosen ciphertext attacks against protocols based on the RSA encryption
+ * standard PKCS# 1" Crypto 98
+ * <li>Manger, "A chosen ciphertext attack on RSA optimal asymmetric encryption padding (OAEP)
+ * as standardized in PKCS# 1 v2.0", Crypto 2001 This paper shows that OAEP is susceptible
+ * to a chosen ciphertext attack if error messages distinguish between different failure
+ * condidtions.
+ * <li>Bardou, Focardi, Kawamoto, Simionato, Steel, Tsay "Efficient Padding Oracle Attacks on
+ * Cryptographic Hardware", Crypto 2012 The paper shows that small differences on what
+ * information an attacker recieves can make a big difference on the number of chosen
+ * message necessary for an attack.
+ * <li>Smart, "Errors matter: Breaking RSA-based PIN encryption with thirty ciphertext validity
+ * queries" RSA conference, 2010 This paper shows that padding oracle attacks can be
+ * successful with even a small number of queries.
+ * </ul>
+ *
+ * <p><b>Some recent bugs:</b> CVE-2012-5081: Java JSSE provider leaked information through
+ * exceptions and timing. Both the PKCS #1 padding and the OAEP padding were broken:
+ * http://www-brs.ub.ruhr-uni-bochum.de/netahtml/HSS/Diss/MeyerChristopher/diss.pdf
+ *
+ * <p><b>What this test does not (yet) cover:</b>
+ *
+ * <ul>
+ * <li> A previous version of one of the provider leaked the block type. (when was this fixed?)
+ * <li> Some attacks require a large number of ciphertexts to be detected if random ciphertexts
+ * are used. Such problems require specifically crafted ciphertexts to run in a unit test.
+ * E.g. "Attacking RSA-based Sessions in SSL/TLS" by V. Klima, O. Pokorny, and T. Rosa:
+ * https://eprint.iacr.org/2003/052/
+ * <li> Timing leakages because of differences in parsing the padding (e.g. CVE-2015-7827) Such
+ * differences are too small to be reliably detectable in unit tests.
+ * </ul>
+ */
+ @SuppressWarnings("InsecureCipherMode")
+ public void testExceptions(String algorithm) throws Exception {
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
+ keygen.initialize(1024);
+ KeyPair keypair = keygen.genKeyPair();
+ SecureRandom rand = new SecureRandom();
+ Cipher c = Cipher.getInstance(algorithm);
+ byte[] ciphertext = new byte[1024 / 8];
+ HashSet<String> exceptions = new HashSet<String>();
+ final int samples = 1000;
+ for (int i = 0; i < samples; i++) {
+ rand.nextBytes(ciphertext);
+ ciphertext[0] &= (byte) 0x7f;
+ try {
+ c.init(Cipher.DECRYPT_MODE, keypair.getPrivate());
+ c.doFinal(ciphertext);
+ } catch (Exception ex) {
+ exceptions.add(ex.toString());
+ }
+ }
+ if (exceptions.size() > 1) {
+ System.out.println("Exceptions for " + algorithm);
+ for (String s : exceptions) {
+ System.out.println(s);
+ }
+ fail("Exceptions leak information about the padding for " + algorithm);
+ }
+ }
+
+ /**
+ * Tests the exceptions for RSA decryption with PKCS1Padding. PKCS1Padding is susceptible to
+ * chosen message attacks. Nonetheless, to minimize the damage of such an attack an implementation
+ * should minimize the information about the failure in the padding.
+ */
+ public void testExceptionsPKCS1() throws Exception {
+ testExceptions("RSA/ECB/PKCS1PADDING");
+ }
+
+ public void testGetExceptionsOAEP() throws Exception {
+ testExceptions("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/RsaKeyTest.java b/java/com/google/security/wycheproof/testcases/RsaKeyTest.java
new file mode 100644
index 0000000..26480b6
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/RsaKeyTest.java
@@ -0,0 +1,139 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import junit.framework.TestCase;
+
+/**
+ * Tests RSA keys. Signatures and encryption are tested in different tests.
+ *
+ * @author bleichen@google.com (Daniel Bleichenbacher)
+ */
+// TODO(bleichen):
+// - Add checks for bad random numbers
+// - expect keys with e=1 to be rejected
+// - expect keys with e=0 to be rejected
+// - document stuff
+// - Maybe also check encodings of private keys.
+// - Test multi prime RSA
+// - Tests for alternative representations:
+// many libraries sort the primes as: p > q (but not all)
+// some libraries compute d mod lambda(n)
+// paramaters p,q,... are not really required
+// - checks for bad random number generation
+public class RsaKeyTest extends TestCase {
+
+ public static final String ENCODED_PUBLIC_KEY =
+ "30819f300d06092a864886f70d010101050003818d0030818902818100ab9014"
+ + "dc47d44b6d260fc1fef9ab022042fd9566e9d7b60c54100cb6e1d4edc9859046"
+ + "7d0502c17fce69d00ac5efb40b2cb167d8a44ab93d73c4d0f109fb5a26c2f882"
+ + "3236ff517cf84412e173679cfae42e043b6fec81f9d984b562517e6febe1f722"
+ + "95dbc3fdfc19d3240aa75515563f31dad83563f3a315acf9a0b351a23f020301"
+ + "0001";
+
+ private void checkPrivateCrtKey(RSAPrivateCrtKey key, int expectedKeySize) throws Exception {
+ BigInteger p = key.getPrimeP();
+ BigInteger q = key.getPrimeQ();
+ BigInteger n = key.getModulus();
+ BigInteger e = key.getPublicExponent();
+ BigInteger d = key.getPrivateExponent();
+ BigInteger dp = key.getPrimeExponentP();
+ BigInteger dq = key.getPrimeExponentQ();
+ BigInteger crtCoeff = key.getCrtCoefficient();
+
+ // Simple test that (n,d,e) is a valid RSA key.
+ assertEquals(n, p.multiply(q));
+ assertEquals(expectedKeySize, n.bitLength());
+ int certainty = 80;
+ assertTrue(p.isProbablePrime(certainty));
+ assertTrue(q.isProbablePrime(certainty));
+ // Very simple checks for weak random number generators.
+ RandomUtil.checkPrime(p);
+ RandomUtil.checkPrime(q);
+ assertTrue(d.bitLength() > expectedKeySize / 2);
+ // TODO(bleichen): Keys that are very imbalanced can be broken with elliptic curve factoring.
+ // Add other checks. E.g. for the size of dp and dq
+ assertTrue(p.bitLength() > 256);
+ assertTrue(q.bitLength() > 256);
+ BigInteger p1 = p.subtract(BigInteger.ONE);
+ BigInteger q1 = q.subtract(BigInteger.ONE);
+ BigInteger phi = p1.multiply(q1);
+ BigInteger order = phi.divide(p1.gcd(q1)); // maximal order of elements
+ assertEquals(BigInteger.ONE, d.multiply(e).mod(order));
+ assertEquals(d.mod(p1), dp.mod(p1));
+ assertEquals(d.mod(q1), dq.mod(q1));
+ assertEquals(q.multiply(crtCoeff).mod(p), BigInteger.ONE);
+ }
+
+ private void checkPublicKey(RSAPublicKey pub, RSAPrivateKey priv) {
+ assertEquals(pub.getModulus(), priv.getModulus());
+ BigInteger e = pub.getPublicExponent();
+ // Checks that e > 1. [CVE-1999-1444]
+ assertEquals(e.compareTo(BigInteger.ONE), 1);
+ }
+
+ private void checkKeyPair(KeyPair keypair, int keySizeInBits) throws Exception {
+ RSAPublicKey pub = (RSAPublicKey) keypair.getPublic();
+ RSAPrivateKey priv = (RSAPrivateKey) keypair.getPrivate();
+ if (priv instanceof RSAPrivateCrtKey) {
+ checkPrivateCrtKey((RSAPrivateCrtKey) priv, keySizeInBits);
+ } else {
+ // Using a CRT key leads to 6-7 times better performance than not using the CRT.
+ // Such a perfomance loss makes a library almost useless. Thus we consider this
+ // a bug.
+ fail("Expecting an RSAPrivateCrtKey instead of " + priv.getClass().getName());
+ }
+ checkPublicKey(pub, priv);
+ }
+
+ public void testKeyGenerationSize(int keySizeInBits) throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(keySizeInBits);
+ KeyPair keypair = keyGen.genKeyPair();
+ checkKeyPair(keypair, keySizeInBits);
+ }
+
+ public void testKeyGeneration() throws Exception {
+ testKeyGenerationSize(1024);
+ testKeyGenerationSize(2048);
+ }
+
+ /**
+ * Checks whether decoding and again encoding an RSA public key results
+ * in the same encoding.
+ * This is a regression test. Failing this test implies that the encoding has changed.
+ * Such a failure does not need to be a bug, since several encoding for the same key are
+ * possible.
+ */
+ public void testEncodeDecodePublic() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ byte[] encoded = TestUtil.hexToBytes(ENCODED_PUBLIC_KEY);
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
+ RSAPublicKey pub = (RSAPublicKey) kf.generatePublic(spec);
+ assertEquals("The test assumes that the public key is in X.509 format",
+ "X.509", pub.getFormat());
+ assertEquals(ENCODED_PUBLIC_KEY, TestUtil.bytesToHex(pub.getEncoded()));
+ }
+}
diff --git a/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java b/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java
new file mode 100644
index 0000000..5b33aa1
--- /dev/null
+++ b/java/com/google/security/wycheproof/testcases/RsaSignatureTest.java
@@ -0,0 +1,140 @@
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.wycheproof;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+import junit.framework.TestCase;
+
+/** Tests RSA signature schemes. */
+// TODO(bleichen):
+// - maybe add tests with invalid keys.
+// - So far only PKCS #1 signatures are tested. But RSA-PSS becomes more popular.
+// - document stuff
+// - Join other RSA tests
+public class RsaSignatureTest extends TestCase {
+ static final RSAPublicKeySpec RSA_KEY1 =
+ new RSAPublicKeySpec(
+ new BigInteger(
+ "ab9014dc47d44b6d260fc1fef9ab022042fd9566e9d7b60c54100cb6e1d4edc9"
+ + "8590467d0502c17fce69d00ac5efb40b2cb167d8a44ab93d73c4d0f109fb5a26"
+ + "c2f8823236ff517cf84412e173679cfae42e043b6fec81f9d984b562517e6feb"
+ + "e1f72295dbc3fdfc19d3240aa75515563f31dad83563f3a315acf9a0b351a23f",
+ 16),
+ new BigInteger("65537"));
+ static final String ALGORITHM_KEY1 = "SHA256WithRSA";
+
+ public void testBasic() throws Exception {
+ String algorithm = "SHA256WithRSA";
+ String hashAlgorithm = "SHA-256";
+ String message = "Hello";
+ int keysize = 2048;
+
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(keysize);
+ KeyPair keyPair = keyGen.generateKeyPair();
+ RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
+
+ byte[] messageBytes = message.getBytes("UTF-8");
+ Signature signer = Signature.getInstance(algorithm);
+ Signature verifier = Signature.getInstance(algorithm);
+ signer.initSign(priv);
+ signer.update(messageBytes);
+ byte[] signature = signer.sign();
+ verifier.initVerify(pub);
+ verifier.update(messageBytes);
+ assertTrue(verifier.verify(signature));
+
+ // Extract some parameters.
+ byte[] rawHash = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
+
+ // Print keys and signature, so that it can be used to generate new test vectors.
+ System.out.println("Message:" + message);
+ System.out.println("Hash:" + TestUtil.bytesToHex(rawHash));
+ System.out.println("Public key:");
+ System.out.println("Modulus:" + pub.getModulus().toString());
+ System.out.println("E:" + pub.getPublicExponent().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
+ System.out.println("Private key:");
+ System.out.println("D:" + priv.getPrivateExponent().toString());
+ System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
+ System.out.println("Signature:" + TestUtil.bytesToHex(signature));
+ }
+
+ /**
+ * Signatures with legacy encoding. Such signatures are sometimes accepted to be compatible with
+ * previously buggy implementations.
+ */
+ static final String[] LEGACY_SIGNATURES_KEY1 = {
+ // A signature where the NULL parameter is missing in the ASN encoding.
+ // padding = 302f300b06096086480165030402010420532eaabd9574880dbf
+ // 76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25
+ "253e1d19bbe91064f2364c1e7db3ba8eb6dc5b19202e440eab6fbdf28c8c6ec0"
+ + "5b812983713c338c72b6e99b8edf506a89ff9fc8e5c2c52362097a56dc228060"
+ + "eca01e1ff318c6c81617691438703411c1f953b21cd74331f87c9b8b189fdffd"
+ + "fe8550bd2bd1d47be915f8604a0f472199dd705e19b1b815f99b68d60bc257c7",
+ };
+
+ /**
+ * Tests legacy signatures. In this context we use the term legacy signatures for signatures that
+ * are not conforming to the PKCS #1 standard, but are sometimes generated by buggy signers. So
+ * far this test considers both accepting and rejecting such signatures as valid behavior.
+ *
+ * <p>Currently we check for just one type of legacy signatures: i.e., a missing NULL parameter in
+ * the ASN encoding of the hash. BouncyCastle and the SunJCE accept this signature, Conscrypt does
+ * not.
+ *
+ * <p>Some references that support accepting this signature:
+ * https://codereview.chromium.org/1690123002/
+ * https://groups.google.com/a/chromium.org/forum/#!topic/chromium-reviews/Jo5S7HtEABI claims that
+ * 7% of the responses in the Online Certificate Status Protocol (OCSP) miss the NULL parameter
+ */
+ public void testLegacySignatures() throws Exception {
+ RSAPublicKeySpec key = RSA_KEY1;
+ String algorithm = ALGORITHM_KEY1;
+ byte[] message = "Test".getBytes("UTF-8");
+ Signature verifier = Signature.getInstance(algorithm);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ PublicKey pub = kf.generatePublic(key);
+ for (String signature : LEGACY_SIGNATURES_KEY1) {
+ byte[] signatureBytes = TestUtil.hexToBytes(signature);
+ verifier.initVerify(pub);
+ verifier.update(message);
+ boolean verified = false;
+ try {
+ verified = verifier.verify(signatureBytes);
+ } catch (SignatureException ex) {
+ verified = false;
+ }
+ if (verified) {
+ System.out.println("Verfied legacy signature:" + signature);
+ } else {
+ System.out.println("Rejected legacy signature:" + signature);
+ }
+ }
+ }
+}