1/* 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 4894151 7055362 27 * @summary known answer test for OAEP encryption 28 * @author Andreas Sterbenz 29 */ 30 31import java.io.*; 32import java.math.BigInteger; 33import java.util.*; 34import java.util.regex.*; 35 36import java.security.*; 37import java.security.spec.*; 38 39import javax.crypto.*; 40 41/** 42 * Known answer test for OAEP encryption. The "oaep-vect.txt" file was taken 43 * from the RSA Security web site. It contains a number of test cases using 44 * keys of various lengths. 45 * 46 * Note that we only test decryption. We cannot do a KAT encryption test 47 * because our APIs do now allow us to explicitly specify the seed. 48 * Encryption is tested in a different test case. 49 */ 50public class TestOAEP_KAT { 51 52 private final static String BASE = System.getProperty("test.src", "."); 53 54 private static BigInteger n, e, d, p, q, pe, qe, coeff; 55 56 private static byte[] plainText, seed, cipherText, cipherText2; 57 58 public static void main(String[] args) throws Exception { 59 long start = System.currentTimeMillis(); 60 Provider provider = Security.getProvider("SunJCE"); 61 Provider kfProvider = Security.getProvider("SunRsaSign"); 62 System.out.println("Testing provider " + provider.getName() + "..."); 63 Cipher c = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", provider); 64 KeyFactory kf = KeyFactory.getInstance("RSA", kfProvider); 65 try (InputStream in = new FileInputStream(new File(BASE, "oaep-vect.txt")); 66 BufferedReader reader = 67 new BufferedReader(new InputStreamReader(in, "UTF8"))) { 68 while (true) { 69 String line = reader.readLine(); 70 if (line == null) { 71 break; 72 } 73 line = line.trim(); 74 if (line.length() == 0) { 75 continue; 76 } 77 if (line.equals("# RSA modulus n:")) { 78 n = parseNumber(reader); 79 } else if (line.equals("# RSA public exponent e:")) { 80 e = parseNumber(reader); 81 } else if (line.equals("# RSA private exponent d:")) { 82 d = parseNumber(reader); 83 } else if (line.equals("# Prime p:")) { 84 p = parseNumber(reader); 85 } else if (line.equals("# Prime q:")) { 86 q = parseNumber(reader); 87 } else if (line.equals("# p's CRT exponent dP:")) { 88 pe = parseNumber(reader); 89 } else if (line.equals("# q's CRT exponent dQ:")) { 90 qe = parseNumber(reader); 91 } else if (line.equals("# CRT coefficient qInv:")) { 92 coeff = parseNumber(reader); 93 } else if (line.equals("# Message to be encrypted:")) { 94 plainText = parseBytes(reader); 95 } else if (line.equals("# Seed:")) { 96 seed = parseBytes(reader); 97 } else if (line.equals("# Encryption:")) { 98 cipherText = parseBytes(reader); 99 // do encryption test first 100 KeySpec pubSpec = new RSAPublicKeySpec(n, e); 101 PublicKey pubKey = kf.generatePublic(pubSpec); 102 c.init(Cipher.ENCRYPT_MODE, pubKey, new MyRandom(seed)); 103 cipherText2 = c.doFinal(plainText); 104 if (Arrays.equals(cipherText2, cipherText) == false) { 105 throw new Exception("Encryption mismatch"); 106 } 107 // followed by decryption test 108 KeySpec privSpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, pe, qe, coeff); 109 PrivateKey privKey = kf.generatePrivate(privSpec); 110 c.init(Cipher.DECRYPT_MODE, privKey); 111 byte[] dec = c.doFinal(cipherText); 112 if (Arrays.equals(plainText, dec) == false) { 113 throw new Exception("Decryption mismatch"); 114 } 115 } else if (line.startsWith("# ------------------------------")) { 116 // ignore, do not print 117 } else { 118 // unknown line (comment), print 119 System.out.println(": " + line); 120 } 121 } 122 } 123 long stop = System.currentTimeMillis(); 124 System.out.println("Done (" + (stop - start) + " ms)."); 125 } 126 127 private static BigInteger parseNumber(BufferedReader reader) throws IOException { 128 return new BigInteger(1, parseBytes(reader)); 129 } 130 131 private static byte[] parseBytes(BufferedReader reader) throws IOException { 132 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 133 while (true) { 134 String line = reader.readLine(); 135 if (line == null) { 136 throw new EOFException("Unexpected EOF"); 137 } 138 line = line.trim(); 139 if (line.length() == 0) { 140 break; 141 } 142 buffer.write(parse(line)); 143 } 144 return buffer.toByteArray(); 145 } 146 147 public static byte[] parse(String s) { 148 try { 149 int n = s.length(); 150 ByteArrayOutputStream out = new ByteArrayOutputStream(n / 3); 151 StringReader r = new StringReader(s); 152 while (true) { 153 int b1 = nextNibble(r); 154 if (b1 < 0) { 155 break; 156 } 157 int b2 = nextNibble(r); 158 if (b2 < 0) { 159 throw new RuntimeException("Invalid string " + s); 160 } 161 int b = (b1 << 4) | b2; 162 out.write(b); 163 } 164 return out.toByteArray(); 165 } catch (IOException e) { 166 throw new RuntimeException(e); 167 } 168 } 169 170 public static byte[] b(String s) { 171 return parse(s); 172 } 173 174 private static int nextNibble(StringReader r) throws IOException { 175 while (true) { 176 int ch = r.read(); 177 if (ch == -1) { 178 return -1; 179 } else if ((ch >= '0') && (ch <= '9')) { 180 return ch - '0'; 181 } else if ((ch >= 'a') && (ch <= 'f')) { 182 return ch - 'a' + 10; 183 } else if ((ch >= 'A') && (ch <= 'F')) { 184 return ch - 'A' + 10; 185 } 186 } 187 } 188 189} 190 191class MyRandom extends SecureRandom { 192 193 private byte[] source; 194 private int count; 195 196 MyRandom(byte[] source) { 197 this.source = (byte[]) source.clone(); 198 count = 0; 199 } 200 201 public void nextBytes(byte[] bytes) { 202 if (bytes.length > source.length - count) { 203 throw new RuntimeException("Insufficient random data"); 204 } 205 System.arraycopy(source, count, bytes, 0, bytes.length); 206 count += bytes.length; 207 } 208} 209