// Copyright 2013, Square, Inc. package com.squareup.crypto.rsa; import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.engines.RSAEngine; import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.junit.Assert; /** RSA test vectors. */ public final class NativeRSAVectors { public static class TestVector { public final BigInteger message; public final BigInteger signed; private final RSAPrivateCrtKeyParameters key; private static BigInteger decode(String hex) { return new BigInteger(hex, 16); } // CHECKSTYLE.OFF: ParameterNumber public TestVector(String message, String signed, String p, String dP, String q, String dQ, String qInv, String privateExponent, String modulus, String publicExponent) { this(decode(message), decode(signed), new RSAPrivateCrtKeyParameters(decode(modulus), decode(publicExponent), decode(privateExponent), decode(p), decode(q), decode(dP), decode(dQ), decode(qInv))); } // CHECKSTYLE.ON: ParameterNumber public TestVector(BigInteger message, BigInteger signed, RSAPrivateCrtKeyParameters key) { this.message = message; this.signed = signed; this.key = key; } public RSAPrivateCrtKeyParameters getPrivateKey() { return key; } public RSAKeyParameters getPublicKey() { return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent()); } private static String hex(BigInteger value) { String result = value.toString(16); if (result.length() % 2 == 1) { result = "0" + result; } return result; } /** Outputs the buffer as Java hex string. */ private static void printHexConstant(BigInteger value) { String hex = hex(value); System.out.print('"'); boolean first = true; for (int i = 0; i < hex.length(); i += 80) { if (first) { first = false; } else { System.out.println('"'); System.out.print(" + \""); } int end = Math.min(hex.length(), i + 80); System.out.print(hex.substring(i, end)); } System.out.print('"'); } public void printJavaConstructorFor() { System.out.println("new TestVector("); printHexConstant(message); System.out.println(','); printHexConstant(signed); System.out.println(','); printHexConstant(key.getP()); System.out.println(','); printHexConstant(key.getDP()); System.out.println(','); printHexConstant(key.getQ()); System.out.println(','); printHexConstant(key.getDQ()); System.out.println(','); printHexConstant(key.getQInv()); System.out.println(','); printHexConstant(key.getExponent()); System.out.println(','); printHexConstant(key.getModulus()); System.out.println(','); printHexConstant(key.getPublicExponent()); System.out.println(");"); } } // Generated by main(). public static final TestVector VECTOR1 = new TestVector( "6f519638774463912c6f45b35505a7498136d6ec5e3603bdebc70c839c9703f077eaf2e053bc6572" + "f01602d23ba7f4a24647b08a7de2ed4dcf5d1540493671a2", "2013391c0207181ef9050c75b8935efac252a109180b0fe57a5bbcd50ef643c061944a241949afed" + "56b48a5cf2fa94861445c2ba042605520296f1ae1220f047", "dce85acf2f4f8aff8c30a5259a9722a4d501316ea76c710f2f5454a3f8f663c9", "934591df74dfb1ffb2cb18c3bc64c1c338ab7649c4f2f60a1f8d8dc2a5f997db", "a3538816ee0da46b4929fa5744e170cd63a3e08c90764409ee0790571e783fab", "6ce25ab9f4091847861bfc3a2deba088ed17eb08604ed8069eafb58f69a57fc7", "49c3b079c92a8054318d19a572cb69db6c95c7141b4bb48f4a801b74e82cad4c", "5df559b9b94918e3d7266e710e98eb23a8e3887ba38298ec3b9668cbccec28443930a002cf1fef2d" + "d3c3200dff617b35472f91ac68b597a74b77078ac7f2fc8b", "8cf0069695eda555c2b9a5a995e560b57d554cb97543e56259619d31b3623c67d604d2ea540d162f" + "92ff4f91de8acc42236c6c7dd4f318940e8e704b435b1e43", "03"); public static final TestVector VECTOR2 = new TestVector( "5b2db76130015d5d37e792d88e337238083419854a285b8edaf6a002f686c56447c029735e152e4f" + "dc3e0a20ac46fc7534a9ccf5cd4bc5d0c03d6a98889593bf1dc8b8f8f2c84fe76e5b4c1cedca8f15" + "fc00be453dd934acbb7ce25a2e12151f7877b0f0985ac861708e478aecb2e3100f1bb057f9aab6ad" + "eeb8b619262ccc04", "81fcb1e408fde7f24faa75e615ee8d05aad7dc1ffc50084b3c4c5bbbce3967d2e92dac5668ab8e96" + "617b819ea58d9507af9f3c2b99308c7ad50229352982311ae359a1e71b060278d33f333b938e15ba" + "f7449873952da5c2e5a1528f71a96d3ecdd73e3e4978467e778ae57084c5fe892042d7a7660f42f5" + "8bf5d2dcde36a6bf", "c6a81281a8373392411b68b3564974f831e143a54f3c6ecf7bfd73b468269f22208b28159595c6bf" + "c7ef556b0abdf58bfde991918483634e174246ad12500e79", "84700c567024cd0c2b679b2239864dfacbeb826e34d2f48a52a8f7cd9ac46a16c05cc563b90e847f" + "da9f8e475c7ea3b2a946610badacecdeba2c2f1e0c355efb", "ba504e74e31dd9fc9521a1cbf9bcf07730cc1961e330b015c6c75f65511b63dea8658b22cf5e12b1" + "3dcc8421949a976c93bcb6e6182131701be50b8b03ad7a97", "7c3589a34213e6a8636bc132a67df5a4cb32bb969775cab92f2f94ee361242947043b21734e961cb" + "7e8858166311ba48627dcf44101620f567ee07b20273a70f", "707555183d8a1f471eeae2c0deb4404e105195f169d7540e6a306cab32a9b757afa6fbf46435a4a5" + "6b8a7520fd0a0b83e66973aac303957855eecbb080d71f39", "6062f49144848238a3a0d34b13d3f99378f1940ed805298ea44c32d1575d3af2f6a709fd6f6cc852" + "570ac2ff6e131a8459255196d00abcbf75dcdc75461a067c4deeffcf6542d1351595f4250bfeafe1" + "d2dd40dd8fe09553b03ef97f7dfcbc60306bad32d588a4242d9f9ae2f48208dff34804d074ed3891" + "fd6a250ab5ee718b", "90946ed9e6c6c354f5713cf09dbdf65d356a5e164407be55f6724c3a030bd86c71fa8efc27232c7b" + "8290247f251ca7c685b7fa6238101b1f30cb4aafe92709bbf5dee0ada339475e769df8b6e2046d42" + "1ef93e538a3dfee2cb234958f63d1d9111923704a540cfa74a2b41e10e1b9a487e924fb04c086999" + "2f4689c826e3335f", "03"); public static final TestVector VECTOR3 = new TestVector( "1796fc3df7b7d80c8168231a2c42c084ae6d1acb5e83fd4d18d210168b9ace4699e4f3dce06dfca8" + "f9f094b4a48390eb41c44bb0c2c9f305e33a68062b4121435af5d497fbbc83484ac01480463c4708" + "b7d567f1c9f61baba3d09195670ad2faac8e4cb6d2a131e70f55aab438eaf3e3935417bf431c788d" + "7f7d6f7c9d7229ef0b4a2ac0811aa7eb053091fd7b81999db88fb8205a019d197e3c94b6f57b5fc6" + "ddb159e4660b1b44f4616c8888138a942afb4aaaf53d06a08ed1a8b54c56c2517c90d8e09d256f96" + "486a092c4329764a50ee3f6859a06a7338eb06949b6e1afd78852f6b560ab4ad634895c9a6df91f8" + "62af34888031f16095980a8c4808bf3b", "2236fe645c6ab1e13067a6ea56f7c97450d36b44a3d60731d5bdc01a9b780488a628400268422349" + "6226058410306ed5cadeaf3600e0dde6779fd17959a73e4c3464ad4dc7ca85cff51b5a02f9f3e2a1" + "4b1365ba6e396d12406d0b7e6bd806e8f1b52aadf40ddc42d0f80bd63aab73b7d84818fd7a0ef566" + "44350ed241592ab6aa39cb908a82413f4cd629abeb1bcb74043e7a9c5573c5e853771cc214b5575c" + "ed4aa741d073fb3aa83d657a4a219c26b0e5d3070ca8ad083668a7c6e1df6de1c8e0ac8cbac9cafc" + "e24140beac1fe6aded1f71b98a0df6726127bccb13f840efff14d6b855d5d5bf54766e3a441dfddc" + "7830133ce35f825c17372d51976f89ca", "e8d1f3c2fdb5c55a41594493df497d2c52fbe8ec7dc1cf2ebaa28f3a3e82ecfe632588ac6cc22a30" + "1c73f760808b7279977367264a9f734622dacda1b0437e5bbf6ebee514bfc4fb2521a796080b5314" + "ffb12cf84cf666e4e2dcbcfefcea61f11a7c4e4816c5fdf42b7d9d05a037db8709a12c66c6f24d5f" + "17ff72161fe102f5", "9b36a281fe792e3c2b90d86294dba8c837529b4853d68a1f27170a26d45748a9976e5b1d9dd6c6ca" + "bda2a4eb005cf6fbba4cef6edc6a4cd96c91de6bcad7a9927f9f29ee0dd52dfcc36bc50eb0078cb8" + "aa761dfaddf999edec9328a9fdf196a0bc52dedab9d953f81cfe68ae6acfe7af5bc0c84484a188ea" + "0fffa1641540aca3", "a5d11df9631ade978f1006ea2218e41044dbdeb143935912c002cfedfd7e894ab2a566afa90046ce" + "7e9c6d0ed565d2571fb59975563eb1821afd0480db4366d80971015c04d10211bcbf63fe16677f45" + "4e850e447eb31a6f70c9df4cc8920b5990c3bbf77e0634cddd10a1afbca33265a67480676f4499d3" + "b107d5d128c7991f", "6e8b6950ecbc94650a0aaf46c165ed602de7e9cb82623b61d557354953a9b0dc7718ef1fc6002f34" + "546848b48e43e18f6a7910f8e429cbac11fe0300922cef3ab0f600e803360161287f97feb99a54d8" + "df035ed8547766f4f5dbea3330615ce660827d4fa95978893e0b1675286ccc43c44daaef9f831137" + "cb5a8e8b708510bf", "1f5f1c9cc56ee1ff7c8ba85c5115011eba4ac135a1a0c098a96f403915d5bee7630d424c6e1c8704" + "c8bed135c62418a21858e60c4aef0505219568f5b3c4e22c30aad0bb94c9ad497aaa125537f599e0" + "29248e08af67e62c1a4da3e682a7b0b6b7ac60922c04ac83d3fe904d0daa72b8e50dc40b41c8696a" + "7d8b2a7298946b14", "64890084d9c81159d0cf3d1a230c29b1e260737bc91d356eabf67c0c102704e38497b14f5d6ab88d" + "f469bda1db7d2b98d8bdd9b32d81ebde23d583423abdb45a060f3bb02291930165885a3ded14c40e" + "97bd79ee259a00d859ddd39f9b957131ac7d9da4f88d6e5fea3317a1303aae7470ca8fdce5f99d6c" + "3df39e76230ed91e1b4880b1c2e3606f3207f663c0972b070ccb95e4acab6b00a3539819a83cb17e" + "d9bee7f6e5a6cd011e6d07fe0e66a044d7c1c2b6d2c625e164df7a43b58e82de966f1682c8e9ec1e" + "a198cdd843ebdd4f0208f9517620ff0edae4caba9acadde67c4eb3f89783c3cf1d3884cc7ca32396" + "c4861d9357a3d12e6ec0a37b17341dbb", "96cd80c746ac1a06b936dba734923e8ad390ad39adabd02601f1ba12183a875546e389f70c2014d4" + "ee9e9c72c93bc165451cc68cc442e1cd35c044e3581c8e870916d98833da5c82184c875ce39f2615" + "e39c36e53867014486ccbd6f696029ca82bc6c7774d4258fdf4ca371c85805aea92fd7cb58f66c22" + "5ced6db1349645aeb78fd2c70525b4989b753d13a24521c72b092874c45648c26fa2c34eb85c8087" + "5c694b4e6e3ca48048b3f06c6b8b3537facba4addd075d9a552709881bdca981aa86620546efa93a" + "d446405884549e50d143b136fcdaffea9bfdcc63adacba2465b618347811d878b46305e817cfc34e" + "d6ded92b39aca0f86f283d1feb76c8ab", "03"); private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private static final BigInteger SIGNING_EXPONENT = BigInteger.valueOf(3); public static void main(String[] args) throws Exception { // Generate new test vectors in Java format. System.out.println("---- NEW CONSTANTS ----"); generateTestVector(512, 1); generateTestVector(1024, 2); generateTestVector(2048, 3); } private static void generateTestVector(int rsaKeyBits, int suffix) throws Exception { AsymmetricCipherKeyPair pair = generateKeyPair(rsaKeyBits); RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters) pair.getPrivate(); byte[] message = new byte[rsaKeyBits / 8]; SECURE_RANDOM.nextBytes(message); // Clear the top bit to ensure it fits. message[0] &= 0x7F; RSAEngine encoder = new RSAEngine(); encoder.init(true, pair.getPrivate()); byte[] signed = encoder.processBlock(message, 0, message.length); RSAEngine decoder = new RSAEngine(); decoder.init(false, pair.getPublic()); byte[] decoded = decoder.processBlock(signed, 0, message.length); Assert.assertArrayEquals(message, decoded); System.out.println("public static final TestVector VECTOR" + suffix + " = "); new TestVector(new BigInteger(1, message), new BigInteger(1, signed), (RSAPrivateCrtKeyParameters) pair.getPrivate()).printJavaConstructorFor(); System.out.println(); } private static AsymmetricCipherKeyPair generateKeyPair(int rsaKeyBits) throws Exception { RSAKeyPairGenerator generator = new RSAKeyPairGenerator(); generator.init(new RSAKeyGenerationParameters(SIGNING_EXPONENT, SECURE_RANDOM, rsaKeyBits, 12)); return generator.generateKeyPair(); } private NativeRSAVectors() { } }