1 /*
   2  * Copyright (c) 2013, 2018, 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         // SHA-512/224 and SHA-512/256
 134         test(new OAEPParameterSpec("SHA-512/224", "MGF1",
 135                 MGF1ParameterSpec.SHA224, PSource.PSpecified.DEFAULT));
 136         test(new OAEPParameterSpec("SHA-512/224", "MGF1",
 137                 MGF1ParameterSpec.SHA512_224, PSource.PSpecified.DEFAULT));
 138         test(new OAEPParameterSpec("SHA-512/256", "MGF1",
 139                 MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
 140         test(new OAEPParameterSpec("SHA-512/256", "MGF1",
 141                 MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
 142 
 143         if (failed) {
 144             throw new Exception("Test failed");
 145         }
 146     }
 147 
 148     /*
 149      * Test with one byte, the max bytes, and the max + 1 bytes allowed by
 150      * the RSA key size and the digest algorithm
 151      */
 152     static void test(OAEPParameterSpec spec) throws Exception {
 153         int dlen = 0;
 154         String algo;
 155 
 156         // For default OAEPParameterSpec case (SHA1)
 157         if (spec == null) {
 158             dlen = 20;
 159             algo = "Default";
 160         } else {
 161             // Use the digest algorith provided in the spec
 162             algo = spec.getDigestAlgorithm();
 163             if (algo.equals("MD5")) {
 164                 dlen = 16;
 165             } else if (algo.equals("SHA1")) {
 166                 dlen = 20;
 167             } else if (algo.equals("SHA-224") || algo.equals("SHA-512/224")) {
 168                 dlen = 28;
 169             } else if (algo.equals("SHA-256") || algo.equals("SHA-512/256")) {
 170                 dlen = 32;
 171             } else if (algo.equals("SHA-384")) {
 172                 dlen = 48;
 173             } else if (algo.equals("SHA-512")) {
 174                 dlen = 64;
 175             }
 176         }
 177 
 178         // OAEP maximum length for a given digest algorith & RSA key length
 179         int max = ((publicKey.getModulus().bitLength() / 8) - (2 * dlen) - 2);
 180 
 181         // Test with data length of 1
 182         try {
 183             testEncryptDecrypt(spec, 1);
 184         } catch (Exception e) {
 185             System.out.println(algo + " failed with data length of 1");
 186             e.printStackTrace();
 187             failed = true;
 188         }
 189 
 190         // Test with data length of maximum allowed
 191         try {
 192             testEncryptDecrypt(spec, max);
 193         } catch (Exception e) {
 194             System.out.println(algo + " failed with data length of " + max);
 195             e.printStackTrace();
 196             failed = true;
 197         }
 198 
 199         // Test with data length of maximum allowed + 1
 200         try {
 201             testEncryptDecrypt(spec, max + 1);
 202             throw new Exception();
 203         } catch (IllegalBlockSizeException ie) {
 204                 // expected to fail
 205         } catch (Exception e) {
 206             System.err.println(algo + " failed with data length of " +
 207                     (max + 1));
 208             e.printStackTrace();
 209             failed = true;
 210 
 211         }
 212     }
 213 
 214     private static void testEncryptDecrypt(OAEPParameterSpec spec,
 215             int dataLength) throws Exception {
 216 
 217         System.out.print("Testing OAEP with hash ");
 218         if (spec != null) {
 219             System.out.print(spec.getDigestAlgorithm() + " and MGF " +
 220                 ((MGF1ParameterSpec)spec.getMGFParameters()).
 221                     getDigestAlgorithm());
 222         } else {
 223             System.out.print("Default");
 224         }
 225         System.out.println(", " + dataLength + " bytes");
 226 
 227         Cipher c = Cipher.getInstance("RSA/ECB/OAEPPadding", cp);
 228         if (spec != null) {
 229             c.init(Cipher.ENCRYPT_MODE, publicKey, spec);
 230         } else {
 231             c.init(Cipher.ENCRYPT_MODE, publicKey);
 232         }
 233 
 234         byte[] data = new byte[dataLength];
 235         byte[] enc = c.doFinal(data);
 236         if (spec != null) {
 237             c.init(Cipher.DECRYPT_MODE, privateKey, spec);
 238         } else {
 239             c.init(Cipher.DECRYPT_MODE, privateKey);
 240         }
 241         byte[] dec = c.doFinal(enc);
 242         if (Arrays.equals(data, dec) == false) {
 243             throw new Exception("Data does not match");
 244         }
 245     }
 246 }