1/*
2 * Copyright (c) 2003, 2012, 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
27 * @summary encryption/decryption test for OAEP
28 * @author Andreas Sterbenz
29 * @key randomness
30 */
31
32import java.util.*;
33
34import java.security.*;
35
36import javax.crypto.*;
37
38public class TestOAEP {
39
40    private static Provider cp;
41
42    private static PrivateKey privateKey;
43
44    private static PublicKey publicKey;
45
46    private static Random random = new Random();
47
48    public static void main(String[] args) throws Exception {
49        long start = System.currentTimeMillis();
50        cp = Security.getProvider("SunJCE");
51        System.out.println("Testing provider " + cp.getName() + "...");
52        Provider kfp = Security.getProvider("SunRsaSign");
53        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp);
54        kpg.initialize(768);
55        KeyPair kp = kpg.generateKeyPair();
56        privateKey = kp.getPrivate();
57        publicKey = kp.getPublic();
58
59        Cipher.getInstance("RSA/ECB/OAEPwithMD5andMGF1Padding");
60        Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
61        Cipher.getInstance("RSA/ECB/OAEPwithSHA-1andMGF1Padding");
62        Cipher.getInstance("RSA/ECB/OAEPwithSHA-224andMGF1Padding");
63        Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");
64        Cipher.getInstance("RSA/ECB/OAEPwithSHA-384andMGF1Padding");
65        Cipher.getInstance("RSA/ECB/OAEPwithSHA-512andMGF1Padding");
66
67        // basic test using MD5
68        testEncryptDecrypt("MD5", 0);
69        testEncryptDecrypt("MD5", 16);
70        testEncryptDecrypt("MD5", 62);
71        try {
72            testEncryptDecrypt("MD5", 63);
73            throw new Exception("Unexpectedly completed call");
74        } catch (IllegalBlockSizeException e) {
75            // ok
76            System.out.println(e);
77        }
78
79        // basic test using SHA-1
80        testEncryptDecrypt("SHA1", 0);
81        testEncryptDecrypt("SHA1", 16);
82        testEncryptDecrypt("SHA1", 54);
83        try {
84            testEncryptDecrypt("SHA1", 55);
85            throw new Exception("Unexpectedly completed call");
86        } catch (IllegalBlockSizeException e) {
87            // ok
88            System.out.println(e);
89        }
90        // tests alias works
91        testEncryptDecrypt("SHA-1", 16);
92
93        // basic test using SHA-224
94        testEncryptDecrypt("SHA-224", 0);
95        testEncryptDecrypt("SHA-224", 16);
96        testEncryptDecrypt("SHA-224", 38);
97        try {
98            testEncryptDecrypt("SHA-224", 39);
99            throw new Exception("Unexpectedly completed call");
100        } catch (IllegalBlockSizeException e) {
101            // ok
102            System.out.println(e);
103        }
104
105        // basic test using SHA-256
106        testEncryptDecrypt("SHA-256", 0);
107        testEncryptDecrypt("SHA-256", 16);
108        testEncryptDecrypt("SHA-256", 30);
109        try {
110            testEncryptDecrypt("SHA-256", 31);
111            throw new Exception("Unexpectedly completed call");
112        } catch (IllegalBlockSizeException e) {
113            // ok
114            System.out.println(e);
115        }
116
117        // 768 bit key too short for OAEP with 64 byte digest
118        try {
119            testEncryptDecrypt("SHA-512", 1);
120            throw new Exception("Unexpectedly completed call");
121        } catch (InvalidKeyException e) {
122            // ok
123            System.out.println(e);
124        }
125
126        Cipher c;
127        byte[] enc;
128        byte[] data = new byte[16];
129        random.nextBytes(data);
130
131        try {
132            c = Cipher.getInstance("RSA/ECB/OAEPwithFOOandMGF1Padding", cp);
133            throw new Exception("Unexpectedly completed call");
134        } catch (NoSuchPaddingException e) {
135            // ok
136            System.out.println(e);
137        }
138
139        c = Cipher.getInstance("RSA/ECB/OAEPwithMD5andMGF1Padding", cp);
140        // cannot "sign" using OAEP
141        try {
142            c.init(Cipher.ENCRYPT_MODE, privateKey);
143            throw new Exception("Unexpectedly completed call");
144        } catch (InvalidKeyException e) {
145            // ok
146            System.out.println(e);
147        }
148
149        // cannot "verify" using OAEP
150        try {
151            c.init(Cipher.DECRYPT_MODE, publicKey);
152            throw new Exception("Unexpectedly completed call");
153        } catch (InvalidKeyException e) {
154            // ok
155            System.out.println(e);
156        }
157
158        // decryption failure
159        c.init(Cipher.DECRYPT_MODE, privateKey);
160        try {
161            c.doFinal(data);
162            throw new Exception("Unexpectedly completed call");
163        } catch (BadPaddingException e) {
164            // ok
165            System.out.println(e);
166        }
167
168        // wrong hash length
169        c.init(Cipher.ENCRYPT_MODE, publicKey);
170        enc = c.doFinal(data);
171        c = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", cp);
172        c.init(Cipher.DECRYPT_MODE, privateKey);
173        try {
174            c.doFinal(enc);
175            throw new Exception("Unexpectedly completed call");
176        } catch (BadPaddingException e) {
177            // ok
178            System.out.println(e);
179        }
180
181/* MD2 not supported with OAEP
182        // wrong hash value
183        c = Cipher.getInstance("RSA/ECB/OAEPwithMD2andMGF1Padding", cp);
184        c.init(Cipher.DECRYPT_MODE, privateKey);
185        try {
186            c.doFinal(enc);
187            throw new Exception("Unexpectedly completed call");
188        } catch (BadPaddingException e) {
189            // ok
190            System.out.println(e);
191        }
192*/
193
194        // wrong padding type
195        c = Cipher.getInstance("RSA/ECB/PKCS1Padding", cp);
196        c.init(Cipher.ENCRYPT_MODE, publicKey);
197        enc = c.doFinal(data);
198        c = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", cp);
199        c.init(Cipher.DECRYPT_MODE, privateKey);
200        try {
201            c.doFinal(enc);
202            throw new Exception("Unexpectedly completed call");
203        } catch (BadPaddingException e) {
204            // ok
205            System.out.println(e);
206        }
207
208        long stop = System.currentTimeMillis();
209        System.out.println("Done (" + (stop - start) + " ms).");
210    }
211
212    // NOTE: OAEP can process up to (modLen - 2*digestLen - 2) bytes of data
213    private static void testEncryptDecrypt(String hashAlg, int dataLength) throws Exception {
214        System.out.println("Testing OAEP with hash " + hashAlg + ", " + dataLength + " bytes");
215        Cipher c = Cipher.getInstance("RSA/ECB/OAEPwith" + hashAlg + "andMGF1Padding", cp);
216        c.init(Cipher.ENCRYPT_MODE, publicKey);
217        byte[] data = new byte[dataLength];
218        byte[] enc = c.doFinal(data);
219        c.init(Cipher.DECRYPT_MODE, privateKey);
220        byte[] dec = c.doFinal(enc);
221        if (Arrays.equals(data, dec) == false) {
222            throw new Exception("Data does not match");
223        }
224    }
225}
226