1 /*
2  * Copyright (c) 2003, 2020, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.crypto.provider;
27 
28 import java.util.Arrays;
29 import java.util.Locale;
30 
31 import java.security.*;
32 import java.security.interfaces.*;
33 import java.security.spec.AlgorithmParameterSpec;
34 import java.security.spec.InvalidParameterSpecException;
35 import java.security.spec.MGF1ParameterSpec;
36 
37 import javax.crypto.*;
38 import javax.crypto.spec.PSource;
39 import javax.crypto.spec.OAEPParameterSpec;
40 
41 import sun.security.rsa.*;
42 import sun.security.jca.Providers;
43 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
44 import sun.security.util.KeyUtil;
45 
46 /**
47  * RSA cipher implementation. Supports RSA en/decryption and signing/verifying
48  * using both PKCS#1 v1.5 and OAEP (v2.2) paddings and without padding (raw RSA).
49  * Note that raw RSA is supported mostly for completeness and should only be
50  * used in rare cases.
51  *
52  * Objects should be instantiated by calling Cipher.getInstance() using the
53  * following algorithm names:
54  *  . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 v1.5 padding.
55  *  . "RSA/ECB/OAEPwith<hash>andMGF1Padding" (or "RSA/ECB/OAEPPadding") for
56  *    PKCS#1 v2.2 padding.
57  *  . "RSA/ECB/NoPadding" for rsa RSA.
58  *
59  * We only do one RSA operation per doFinal() call. If the application passes
60  * more data via calls to update() or doFinal(), we throw an
61  * IllegalBlockSizeException when doFinal() is called (see JCE API spec).
62  * Bulk encryption using RSA does not make sense and is not standardized.
63  *
64  * Note: RSA keys should be at least 512 bits long
65  *
66  * @since   1.5
67  * @author  Andreas Sterbenz
68  */
69 public final class RSACipher extends CipherSpi {
70 
71     // constant for an empty byte array
72     private static final byte[] B0 = new byte[0];
73 
74     // mode constant for public key encryption
75     private static final int MODE_ENCRYPT = 1;
76     // mode constant for private key decryption
77     private static final int MODE_DECRYPT = 2;
78     // mode constant for private key encryption (signing)
79     private static final int MODE_SIGN    = 3;
80     // mode constant for public key decryption (verifying)
81     private static final int MODE_VERIFY  = 4;
82 
83     // constant for raw RSA
84     private static final String PAD_NONE  = "NoPadding";
85     // constant for PKCS#1 v1.5 RSA
86     private static final String PAD_PKCS1 = "PKCS1Padding";
87     // constant for PKCS#2 v2.2 OAEP with MGF1
88     private static final String PAD_OAEP_MGF1  = "OAEP";
89 
90     // current mode, one of MODE_* above. Set when init() is called
91     private int mode;
92 
93     // active padding type, one of PAD_* above. Set by setPadding()
94     private String paddingType;
95 
96     // padding object
97     private RSAPadding padding;
98 
99     // cipher parameter for OAEP padding and TLS RSA premaster secret
100     private AlgorithmParameterSpec spec = null;
101 
102     // buffer for the data
103     private byte[] buffer;
104     // offset into the buffer (number of bytes buffered)
105     private int bufOfs;
106 
107     // size of the output
108     private int outputSize;
109 
110     // the public key, if we were initialized using a public key
111     private RSAPublicKey publicKey;
112     // the private key, if we were initialized using a private key
113     private RSAPrivateKey privateKey;
114 
115     // hash algorithm for OAEP
116     private String oaepHashAlgorithm = "SHA-1";
117 
118     // the source of randomness
119     private SecureRandom random;
120 
RSACipher()121     public RSACipher() {
122         paddingType = PAD_PKCS1;
123     }
124 
125     // modes do not make sense for RSA, but allow ECB
126     // see JCE spec
engineSetMode(String mode)127     protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
128         if (mode.equalsIgnoreCase("ECB") == false) {
129             throw new NoSuchAlgorithmException("Unsupported mode " + mode);
130         }
131     }
132 
133     // set the padding type
134     // see JCE spec
engineSetPadding(String paddingName)135     protected void engineSetPadding(String paddingName)
136             throws NoSuchPaddingException {
137         if (paddingName.equalsIgnoreCase(PAD_NONE)) {
138             paddingType = PAD_NONE;
139         } else if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {
140             paddingType = PAD_PKCS1;
141         } else {
142             String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH);
143             if (lowerPadding.equals("oaeppadding")) {
144                 paddingType = PAD_OAEP_MGF1;
145             } else if (lowerPadding.startsWith("oaepwith") &&
146                        lowerPadding.endsWith("andmgf1padding")) {
147                 paddingType = PAD_OAEP_MGF1;
148                 // "oaepwith".length() == 8
149                 // "andmgf1padding".length() == 14
150                 oaepHashAlgorithm =
151                         paddingName.substring(8, paddingName.length() - 14);
152                 // check if MessageDigest appears to be available
153                 // avoid getInstance() call here
154                 if (Providers.getProviderList().getService
155                         ("MessageDigest", oaepHashAlgorithm) == null) {
156                     throw new NoSuchPaddingException
157                         ("MessageDigest not available for " + paddingName);
158                 }
159             } else {
160                 throw new NoSuchPaddingException
161                     ("Padding " + paddingName + " not supported");
162             }
163         }
164     }
165 
166     // return 0 as block size, we are not a block cipher
167     // see JCE spec
engineGetBlockSize()168     protected int engineGetBlockSize() {
169         return 0;
170     }
171 
172     // return the output size
173     // see JCE spec
engineGetOutputSize(int inputLen)174     protected int engineGetOutputSize(int inputLen) {
175         return outputSize;
176     }
177 
178     // no iv, return null
179     // see JCE spec
engineGetIV()180     protected byte[] engineGetIV() {
181         return null;
182     }
183 
184     // see JCE spec
engineGetParameters()185     protected AlgorithmParameters engineGetParameters() {
186         if (spec != null && spec instanceof OAEPParameterSpec) {
187             try {
188                 AlgorithmParameters params =
189                     AlgorithmParameters.getInstance("OAEP",
190                         SunJCE.getInstance());
191                 params.init(spec);
192                 return params;
193             } catch (NoSuchAlgorithmException nsae) {
194                 // should never happen
195                 throw new RuntimeException("Cannot find OAEP " +
196                     " AlgorithmParameters implementation in SunJCE provider");
197             } catch (InvalidParameterSpecException ipse) {
198                 // should never happen
199                 throw new RuntimeException("OAEPParameterSpec not supported");
200             }
201         } else {
202             return null;
203         }
204     }
205 
206     // see JCE spec
engineInit(int opmode, Key key, SecureRandom random)207     protected void engineInit(int opmode, Key key, SecureRandom random)
208             throws InvalidKeyException {
209         try {
210             init(opmode, key, random, null);
211         } catch (InvalidAlgorithmParameterException iape) {
212             // never thrown when null parameters are used;
213             // but re-throw it just in case
214             InvalidKeyException ike =
215                 new InvalidKeyException("Wrong parameters");
216             ike.initCause(iape);
217             throw ike;
218         }
219     }
220 
221     // see JCE spec
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)222     protected void engineInit(int opmode, Key key,
223             AlgorithmParameterSpec params, SecureRandom random)
224             throws InvalidKeyException, InvalidAlgorithmParameterException {
225         init(opmode, key, random, params);
226     }
227 
228     // see JCE spec
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)229     protected void engineInit(int opmode, Key key,
230             AlgorithmParameters params, SecureRandom random)
231             throws InvalidKeyException, InvalidAlgorithmParameterException {
232         if (params == null) {
233             init(opmode, key, random, null);
234         } else {
235             try {
236                 OAEPParameterSpec spec =
237                         params.getParameterSpec(OAEPParameterSpec.class);
238                 init(opmode, key, random, spec);
239             } catch (InvalidParameterSpecException ipse) {
240                 InvalidAlgorithmParameterException iape =
241                     new InvalidAlgorithmParameterException("Wrong parameter");
242                 iape.initCause(ipse);
243                 throw iape;
244             }
245         }
246     }
247 
248     // initialize this cipher
249     @SuppressWarnings("deprecation")
init(int opmode, Key key, SecureRandom random, AlgorithmParameterSpec params)250     private void init(int opmode, Key key, SecureRandom random,
251             AlgorithmParameterSpec params)
252             throws InvalidKeyException, InvalidAlgorithmParameterException {
253         boolean encrypt;
254         switch (opmode) {
255         case Cipher.ENCRYPT_MODE:
256         case Cipher.WRAP_MODE:
257             encrypt = true;
258             break;
259         case Cipher.DECRYPT_MODE:
260         case Cipher.UNWRAP_MODE:
261             encrypt = false;
262             break;
263         default:
264             throw new InvalidKeyException("Unknown mode: " + opmode);
265         }
266         RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
267         if (key instanceof RSAPublicKey) {
268             mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
269             publicKey = (RSAPublicKey)key;
270             privateKey = null;
271         } else { // must be RSAPrivateKey per check in toRSAKey
272             mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
273             privateKey = (RSAPrivateKey)key;
274             publicKey = null;
275         }
276         int n = RSACore.getByteLength(rsaKey.getModulus());
277         outputSize = n;
278         bufOfs = 0;
279         if (paddingType == PAD_NONE) {
280             if (params != null) {
281                 throw new InvalidAlgorithmParameterException
282                 ("Parameters not supported");
283             }
284             padding = RSAPadding.getInstance(RSAPadding.PAD_NONE, n, random);
285             buffer = new byte[n];
286         } else if (paddingType == PAD_PKCS1) {
287             if (params != null) {
288                 if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
289                     throw new InvalidAlgorithmParameterException(
290                             "Parameters not supported");
291                 }
292 
293                 spec = params;
294                 this.random = random;   // for TLS RSA premaster secret
295             }
296             int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2
297                                                    : RSAPadding.PAD_BLOCKTYPE_1;
298             padding = RSAPadding.getInstance(blockType, n, random);
299             if (encrypt) {
300                 int k = padding.getMaxDataSize();
301                 buffer = new byte[k];
302             } else {
303                 buffer = new byte[n];
304             }
305         } else { // PAD_OAEP_MGF1
306             if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) {
307                 throw new InvalidKeyException
308                         ("OAEP cannot be used to sign or verify signatures");
309             }
310             if (params != null) {
311                 if (!(params instanceof OAEPParameterSpec)) {
312                     throw new InvalidAlgorithmParameterException
313                         ("Wrong Parameters for OAEP Padding");
314                 }
315                 spec = params;
316             } else {
317                 spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
318                     MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
319             }
320             padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n,
321                 random, (OAEPParameterSpec)spec);
322             if (encrypt) {
323                 int k = padding.getMaxDataSize();
324                 buffer = new byte[k];
325             } else {
326                 buffer = new byte[n];
327             }
328         }
329     }
330 
331     // internal update method
update(byte[] in, int inOfs, int inLen)332     private void update(byte[] in, int inOfs, int inLen) {
333         if ((inLen == 0) || (in == null)) {
334             return;
335         }
336         if (inLen > (buffer.length - bufOfs)) {
337             bufOfs = buffer.length + 1;
338             return;
339         }
340         System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
341         bufOfs += inLen;
342     }
343 
344     // internal doFinal() method. Here we perform the actual RSA operation
doFinal()345     private byte[] doFinal() throws BadPaddingException,
346             IllegalBlockSizeException {
347         if (bufOfs > buffer.length) {
348             throw new IllegalBlockSizeException("Data must not be longer "
349                 + "than " + buffer.length + " bytes");
350         }
351         byte[] paddingCopy = null;
352         byte[] result = null;
353         try {
354             switch (mode) {
355             case MODE_SIGN:
356                 paddingCopy = padding.pad(buffer, 0, bufOfs);
357                 result = RSACore.rsa(paddingCopy, privateKey, true);
358                 break;
359             case MODE_VERIFY:
360                 byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs);
361                 paddingCopy = RSACore.rsa(verifyBuffer, publicKey);
362                 result = padding.unpad(paddingCopy);
363                 break;
364             case MODE_ENCRYPT:
365                 paddingCopy = padding.pad(buffer, 0, bufOfs);
366                 result = RSACore.rsa(paddingCopy, publicKey);
367                 break;
368             case MODE_DECRYPT:
369                 byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs);
370                 paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false);
371                 result = padding.unpad(paddingCopy);
372                 break;
373             default:
374                 throw new AssertionError("Internal error");
375             }
376             return result;
377         } finally {
378             Arrays.fill(buffer, 0, bufOfs, (byte)0);
379             bufOfs = 0;
380             if (paddingCopy != null             // will not happen
381                     && paddingCopy != buffer    // already cleaned
382                     && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT!
383                 Arrays.fill(paddingCopy, (byte)0);
384             }
385         }
386     }
387 
388     // see JCE spec
engineUpdate(byte[] in, int inOfs, int inLen)389     protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
390         update(in, inOfs, inLen);
391         return B0;
392     }
393 
394     // see JCE spec
engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs)395     protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
396             int outOfs) {
397         update(in, inOfs, inLen);
398         return 0;
399     }
400 
401     // see JCE spec
engineDoFinal(byte[] in, int inOfs, int inLen)402     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
403             throws BadPaddingException, IllegalBlockSizeException {
404         update(in, inOfs, inLen);
405         return doFinal();
406     }
407 
408     // see JCE spec
engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs)409     protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
410             int outOfs) throws ShortBufferException, BadPaddingException,
411             IllegalBlockSizeException {
412         if (outputSize > out.length - outOfs) {
413             throw new ShortBufferException
414                 ("Need " + outputSize + " bytes for output");
415         }
416         update(in, inOfs, inLen);
417         byte[] result = doFinal();
418         int n = result.length;
419         System.arraycopy(result, 0, out, outOfs, n);
420         Arrays.fill(result, (byte)0);
421         return n;
422     }
423 
424     // see JCE spec
engineWrap(Key key)425     protected byte[] engineWrap(Key key) throws InvalidKeyException,
426             IllegalBlockSizeException {
427         byte[] encoded = key.getEncoded();
428         if ((encoded == null) || (encoded.length == 0)) {
429             throw new InvalidKeyException("Could not obtain encoded key");
430         }
431         try {
432             if (encoded.length > buffer.length) {
433                 throw new InvalidKeyException("Key is too long for wrapping");
434             }
435             update(encoded, 0, encoded.length);
436             try {
437                 return doFinal();
438             } catch (BadPaddingException e) {
439                 // should not occur
440                 throw new InvalidKeyException("Wrapping failed", e);
441             }
442         } finally {
443             Arrays.fill(encoded, (byte)0);
444         }
445     }
446 
447     // see JCE spec
448     @SuppressWarnings("deprecation")
engineUnwrap(byte[] wrappedKey, String algorithm, int type)449     protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
450             int type) throws InvalidKeyException, NoSuchAlgorithmException {
451         if (wrappedKey.length > buffer.length) {
452             throw new InvalidKeyException("Key is too long for unwrapping");
453         }
454 
455         boolean isTlsRsaPremasterSecret =
456                 algorithm.equals("TlsRsaPremasterSecret");
457         Exception failover = null;
458         byte[] encoded = null;
459 
460         update(wrappedKey, 0, wrappedKey.length);
461         try {
462             encoded = doFinal();
463         } catch (BadPaddingException e) {
464             if (isTlsRsaPremasterSecret) {
465                 failover = e;
466             } else {
467                 throw new InvalidKeyException("Unwrapping failed", e);
468             }
469         } catch (IllegalBlockSizeException e) {
470             // should not occur, handled with length check above
471             throw new InvalidKeyException("Unwrapping failed", e);
472         }
473 
474         try {
475             if (isTlsRsaPremasterSecret) {
476                 if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
477                     throw new IllegalStateException(
478                             "No TlsRsaPremasterSecretParameterSpec specified");
479                 }
480 
481                 // polish the TLS premaster secret
482                 encoded = KeyUtil.checkTlsPreMasterSecretKey(
483                         ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(),
484                         ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(),
485                         random, encoded, (failover != null));
486             }
487 
488             return ConstructKeys.constructKey(encoded, algorithm, type);
489         } finally {
490             if (encoded != null) {
491                 Arrays.fill(encoded, (byte) 0);
492             }
493         }
494     }
495 
496     // see JCE spec
engineGetKeySize(Key key)497     protected int engineGetKeySize(Key key) throws InvalidKeyException {
498         RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
499         return rsaKey.getModulus().bitLength();
500     }
501 }
502