aboutsummaryrefslogtreecommitdiff
path: root/java/com/google/security/wycheproof/testcases/RsaKeyTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/security/wycheproof/testcases/RsaKeyTest.java')
-rw-r--r--java/com/google/security/wycheproof/testcases/RsaKeyTest.java139
1 files changed, 139 insertions, 0 deletions
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()));
+ }
+}