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