1 /*
   2  * Copyright (c) 2013, 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 8020081 8022669
  27  * @summary encryption/decryption test for using OAEPPadding with
  28  * OAEPParameterSpec specified and not specified during a Cipher.init().
  29  * @author Anthony Scarpino
  30  */
  31 
  32 import java.util.Arrays;
  33 
  34 import java.security.Security;
  35 import java.security.Provider;
  36 import java.security.KeyPair;
  37 import java.security.KeyPairGenerator;
  38 import java.security.interfaces.RSAPrivateKey;
  39 import java.security.interfaces.RSAPublicKey;
  40 import java.security.spec.MGF1ParameterSpec;
  41 
  42 import javax.crypto.Cipher;
  43 import javax.crypto.spec.OAEPParameterSpec;
  44 import javax.crypto.IllegalBlockSizeException;
  45 import javax.crypto.spec.PSource;
  46 
  47 
  48 public class TestOAEPPadding {
  49     private static RSAPrivateKey privateKey;
  50     private static RSAPublicKey publicKey;
  51     static Provider cp;
  52     static boolean failed = false;
  53 
  54     public static void main(String args[]) throws Exception {
  55         cp = Security.getProvider("SunJCE");
  56         System.out.println("Testing provider " + cp.getName() + "...");
  57         Provider kfp = Security.getProvider("SunRsaSign");
  58         KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", kfp);
  59         kpg.initialize(2048);
  60         KeyPair kp = kpg.generateKeyPair();
  61         privateKey = (RSAPrivateKey)kp.getPrivate();
  62         publicKey = (RSAPublicKey)kp.getPublic();
  63 
  64         // Test using a spec with each digest algorithm case
  65         // MD5
  66         test(new OAEPParameterSpec("MD5", "MGF1",
  67                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
  68         test(new OAEPParameterSpec("MD5", "MGF1",
  69                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
  70         test(new OAEPParameterSpec("MD5", "MGF1",
  71                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
  72         test(new OAEPParameterSpec("MD5", "MGF1",
  73                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
  74         test(new OAEPParameterSpec("MD5", "MGF1",
  75                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
  76         // SHA1
  77         test(new OAEPParameterSpec("SHA1", "MGF1",
  78                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
  79         test(new OAEPParameterSpec("SHA1", "MGF1",
  80                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
  81         test(new OAEPParameterSpec("SHA1", "MGF1",
  82                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
  83         test(new OAEPParameterSpec("SHA1", "MGF1",
  84                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
  85         test(new OAEPParameterSpec("SHA1", "MGF1",
  86                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
  87         // For default OAEPParameterSpec case (SHA1)
  88         test(null);
  89         // SHA-224
  90         test(new OAEPParameterSpec("SHA-224", "MGF1",
  91                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
  92         test(new OAEPParameterSpec("SHA-224", "MGF1",
  93                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
  94         test(new OAEPParameterSpec("SHA-224", "MGF1",
  95                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
  96         test(new OAEPParameterSpec("SHA-224", "MGF1",
  97                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
  98         test(new OAEPParameterSpec("SHA-224", "MGF1",
  99                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
 100         // SHA-256
 101         test(new OAEPParameterSpec("SHA-256", "MGF1",
 102                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
 103         test(new OAEPParameterSpec("SHA-256", "MGF1",
 104                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
 105         test(new OAEPParameterSpec("SHA-256", "MGF1",
 106                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
 107         test(new OAEPParameterSpec("SHA-256", "MGF1",
 108                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
 109         test(new OAEPParameterSpec("SHA-256", "MGF1",
 110                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
 111         // SHA-384
 112         test(new OAEPParameterSpec("SHA-384", "MGF1",
 113                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
 114         test(new OAEPParameterSpec("SHA-384", "MGF1",
 115                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
 116         test(new OAEPParameterSpec("SHA-384", "MGF1",
 117                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
 118         test(new OAEPParameterSpec("SHA-384", "MGF1",
 119                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
 120         test(new OAEPParameterSpec("SHA-384", "MGF1",
 121                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
 122         // SHA-512
 123         test(new OAEPParameterSpec("SHA-512", "MGF1",
 124                 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
 125         test(new OAEPParameterSpec("SHA-512", "MGF1",
 126                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
 127         test(new OAEPParameterSpec("SHA-512", "MGF1",
 128                 MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
 129         test(new OAEPParameterSpec("SHA-512", "MGF1",
 130                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
 131         test(new OAEPParameterSpec("SHA-512", "MGF1",
 132                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
 133         if (failed) {
 134             throw new Exception("Test failed");
 135         }
 136     }
 137 
 138     /*
 139      * Test with one byte, the max bytes, and the max + 1 bytes allowed by
 140      * the RSA key size and the digest algorithm
 141      */
 142     static void test(OAEPParameterSpec spec) throws Exception {
 143         int dlen = 0;
 144         String algo;
 145 
 146         // For default OAEPParameterSpec case (SHA1)
 147         if (spec == null) {
 148             dlen = 20;
 149             algo = "Default";
 150         } else {
 151             // Use the digest algorith provided in the spec
 152             algo = spec.getDigestAlgorithm();
 153             if (algo.equals("MD5")) {
 154                 dlen = 16;
 155             } else if (algo.equals("SHA1")) {
 156                 dlen = 20;
 157             } else if (algo.equals("SHA-224")) {
 158                 dlen = 28;
 159             } else if (algo.equals("SHA-256")) {
 160                 dlen = 32;
 161             } else if (algo.equals("SHA-384")) {
 162                 dlen = 48;
 163             } else if (algo.equals("SHA-512")) {
 164                 dlen = 64;
 165             }
 166         }
 167 
 168         // OAEP maximum length for a given digest algorith & RSA key length
 169         int max = ((publicKey.getModulus().bitLength() / 8) - (2 * dlen) - 2);
 170 
 171         // Test with data length of 1
 172         try {
 173             testEncryptDecrypt(spec, 1);
 174         } catch (Exception e) {
 175             System.out.println(algo + " failed with data length of 1");
 176             e.printStackTrace();
 177             failed = true;
 178         }
 179 
 180         // Test with data length of maximum allowed
 181         try {
 182             testEncryptDecrypt(spec, max);
 183         } catch (Exception e) {
 184             System.out.println(algo + " failed with data length of " + max);
 185             e.printStackTrace();
 186             failed = true;
 187         }
 188 
 189         // Test with data length of maximum allowed + 1
 190         try {
 191             testEncryptDecrypt(spec, max + 1);
 192             throw new Exception();
 193         } catch (IllegalBlockSizeException ie) {
 194                 // expected to fail
 195         } catch (Exception e) {
 196             System.err.println(algo + " failed with data length of " +
 197                     (max + 1));
 198             e.printStackTrace();
 199             failed = true;
 200 
 201         }
 202     }
 203 
 204     private static void testEncryptDecrypt(OAEPParameterSpec spec,
 205             int dataLength) throws Exception {
 206 
 207         System.out.print("Testing OAEP with hash ");
 208         if (spec != null) {
 209             System.out.print(spec.getDigestAlgorithm() + " and MGF " +
 210                 ((MGF1ParameterSpec)spec.getMGFParameters()).
 211                     getDigestAlgorithm());
 212         } else {
 213             System.out.print("Default");
 214         }
 215         System.out.println(", " + dataLength + " bytes");
 216 
 217         Cipher c = Cipher.getInstance("RSA/ECB/OAEPPadding", cp);
 218         if (spec != null) {
 219             c.init(Cipher.ENCRYPT_MODE, publicKey, spec);
 220         } else {
 221             c.init(Cipher.ENCRYPT_MODE, publicKey);
 222         }
 223 
 224         byte[] data = new byte[dataLength];
 225         byte[] enc = c.doFinal(data);
 226         if (spec != null) {
 227             c.init(Cipher.DECRYPT_MODE, privateKey, spec);
 228         } else {
 229             c.init(Cipher.DECRYPT_MODE, privateKey);
 230         }
 231         byte[] dec = c.doFinal(enc);
 232         if (Arrays.equals(data, dec) == false) {
 233             throw new Exception("Data does not match");
 234         }
 235     }
 236 }