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 sun.security.rsa;
27 
28 import java.util.*;
29 
30 import java.security.*;
31 import java.security.spec.*;
32 
33 import javax.crypto.BadPaddingException;
34 import javax.crypto.spec.PSource;
35 import javax.crypto.spec.OAEPParameterSpec;
36 
37 import sun.security.jca.JCAUtil;
38 
39 /**
40  * RSA padding and unpadding.
41  *
42  * The various PKCS#1 versions can be found in the IETF RFCs
43  * tracking the corresponding PKCS#1 standards.
44  *
45  *     RFC 2313: PKCS#1 v1.5
46  *     RFC 2437: PKCS#1 v2.0
47  *     RFC 3447: PKCS#1 v2.1
48  *     RFC 8017: PKCS#1 v2.2
49  *
50  * The format of PKCS#1 v1.5 padding is:
51  *
52  *   0x00 | BT | PS...PS | 0x00 | data...data
53  *
54  * where BT is the blocktype (1 or 2). The length of the entire string
55  * must be the same as the size of the modulus (i.e. 128 byte for a 1024 bit
56  * key). Per spec, the padding string must be at least 8 bytes long. That
57  * leaves up to (length of key in bytes) - 11 bytes for the data.
58  *
59  * OAEP padding was introduced in PKCS#1 v2.0 and is a bit more complicated
60  * and has a number of options. We support:
61  *
62  *   . arbitrary hash functions ('Hash' in the specification), MessageDigest
63  *     implementation must be available
64  *   . MGF1 as the mask generation function
65  *   . the empty string as the default value for label L and whatever
66  *     specified in javax.crypto.spec.OAEPParameterSpec
67  *
68  * The algorithms (representations) are forwards-compatible: that is,
69  * the algorithm described in previous releases are in later releases.
70  * However, additional comments/checks/clarifications were added to the
71  * later versions based on real-world experience (e.g. stricter v1.5
72  * format checking.)
73  *
74  * Note: RSA keys should be at least 512 bits long
75  *
76  * @since   1.5
77  * @author  Andreas Sterbenz
78  */
79 public final class RSAPadding {
80 
81     // NOTE: the constants below are embedded in the JCE RSACipher class
82     // file. Do not change without coordinating the update
83 
84     // PKCS#1 v1.5 padding, blocktype 1 (signing)
85     public final static int PAD_BLOCKTYPE_1    = 1;
86     // PKCS#1 v1.5 padding, blocktype 2 (encryption)
87     public final static int PAD_BLOCKTYPE_2    = 2;
88     // nopadding. Does not do anything, but allows simpler RSACipher code
89     public final static int PAD_NONE           = 3;
90     // PKCS#1 v2.1 OAEP padding
91     public final static int PAD_OAEP_MGF1 = 4;
92 
93     // type, one of PAD_*
94     private final int type;
95 
96     // size of the padded block (i.e. size of the modulus)
97     private final int paddedSize;
98 
99     // PRNG used to generate padding bytes (PAD_BLOCKTYPE_2, PAD_OAEP_MGF1)
100     private SecureRandom random;
101 
102     // maximum size of the data
103     private final int maxDataSize;
104 
105     // OAEP: main message digest
106     private MessageDigest md;
107 
108     // OAEP: MGF1
109     private MGF1 mgf;
110 
111     // OAEP: value of digest of data (user-supplied or zero-length) using md
112     private byte[] lHash;
113 
114     /**
115      * Get a RSAPadding instance of the specified type.
116      * Keys used with this padding must be paddedSize bytes long.
117      */
getInstance(int type, int paddedSize)118     public static RSAPadding getInstance(int type, int paddedSize)
119             throws InvalidKeyException, InvalidAlgorithmParameterException {
120         return new RSAPadding(type, paddedSize, null, null);
121     }
122 
123     /**
124      * Get a RSAPadding instance of the specified type.
125      * Keys used with this padding must be paddedSize bytes long.
126      */
getInstance(int type, int paddedSize, SecureRandom random)127     public static RSAPadding getInstance(int type, int paddedSize,
128             SecureRandom random) throws InvalidKeyException,
129             InvalidAlgorithmParameterException {
130         return new RSAPadding(type, paddedSize, random, null);
131     }
132 
133     /**
134      * Get a RSAPadding instance of the specified type, which must be
135      * OAEP. Keys used with this padding must be paddedSize bytes long.
136      */
getInstance(int type, int paddedSize, SecureRandom random, OAEPParameterSpec spec)137     public static RSAPadding getInstance(int type, int paddedSize,
138             SecureRandom random, OAEPParameterSpec spec)
139         throws InvalidKeyException, InvalidAlgorithmParameterException {
140         return new RSAPadding(type, paddedSize, random, spec);
141     }
142 
143     // internal constructor
RSAPadding(int type, int paddedSize, SecureRandom random, OAEPParameterSpec spec)144     private RSAPadding(int type, int paddedSize, SecureRandom random,
145             OAEPParameterSpec spec) throws InvalidKeyException,
146             InvalidAlgorithmParameterException {
147         this.type = type;
148         this.paddedSize = paddedSize;
149         this.random = random;
150         if (paddedSize < 64) {
151             // sanity check, already verified in RSASignature/RSACipher
152             throw new InvalidKeyException("Padded size must be at least 64");
153         }
154         switch (type) {
155         case PAD_BLOCKTYPE_1:
156         case PAD_BLOCKTYPE_2:
157             maxDataSize = paddedSize - 11;
158             break;
159         case PAD_NONE:
160             maxDataSize = paddedSize;
161             break;
162         case PAD_OAEP_MGF1:
163             String mdName = "SHA-1";
164             String mgfMdName = mdName;
165             byte[] digestInput = null;
166             try {
167                 if (spec != null) {
168                     mdName = spec.getDigestAlgorithm();
169                     String mgfName = spec.getMGFAlgorithm();
170                     if (!mgfName.equalsIgnoreCase("MGF1")) {
171                         throw new InvalidAlgorithmParameterException
172                             ("Unsupported MGF algo: " + mgfName);
173                     }
174                     mgfMdName = ((MGF1ParameterSpec)spec.getMGFParameters())
175                             .getDigestAlgorithm();
176                     PSource pSrc = spec.getPSource();
177                     String pSrcAlgo = pSrc.getAlgorithm();
178                     if (!pSrcAlgo.equalsIgnoreCase("PSpecified")) {
179                         throw new InvalidAlgorithmParameterException
180                             ("Unsupported pSource algo: " + pSrcAlgo);
181                     }
182                     digestInput = ((PSource.PSpecified) pSrc).getValue();
183                 }
184                 md = MessageDigest.getInstance(mdName);
185                 mgf = new MGF1(mgfMdName);
186             } catch (NoSuchAlgorithmException e) {
187                 throw new InvalidKeyException("Digest not available", e);
188             }
189             lHash = getInitialHash(md, digestInput);
190             int digestLen = lHash.length;
191             maxDataSize = paddedSize - 2 - 2 * digestLen;
192             if (maxDataSize <= 0) {
193                 throw new InvalidKeyException
194                         ("Key is too short for encryption using OAEPPadding" +
195                          " with " + mdName + " and " + mgf.getName());
196             }
197             break;
198         default:
199             throw new InvalidKeyException("Invalid padding: " + type);
200         }
201     }
202 
203     // cache of hashes of zero length data
204     private static final Map<String,byte[]> emptyHashes =
205         Collections.synchronizedMap(new HashMap<String,byte[]>());
206 
207     /**
208      * Return the value of the digest using the specified message digest
209      * <code>md</code> and the digest input <code>digestInput</code>.
210      * if <code>digestInput</code> is null or 0-length, zero length
211      * is used to generate the initial digest.
212      * Note: the md object must be in reset state
213      */
getInitialHash(MessageDigest md, byte[] digestInput)214     private static byte[] getInitialHash(MessageDigest md,
215         byte[] digestInput) {
216         byte[] result;
217         if ((digestInput == null) || (digestInput.length == 0)) {
218             String digestName = md.getAlgorithm();
219             result = emptyHashes.get(digestName);
220             if (result == null) {
221                 result = md.digest();
222                 emptyHashes.put(digestName, result);
223             }
224         } else {
225             result = md.digest(digestInput);
226         }
227         return result;
228     }
229 
230     /**
231      * Return the maximum size of the plaintext data that can be processed
232      * using this object.
233      */
getMaxDataSize()234     public int getMaxDataSize() {
235         return maxDataSize;
236     }
237 
238     /**
239      * Pad the data and return the padded block.
240      */
pad(byte[] data)241     public byte[] pad(byte[] data) throws BadPaddingException {
242         return pad(data, 0, data.length);
243     }
244 
245     /**
246      * Pad the data and return the padded block.
247      */
pad(byte[] data, int ofs, int len)248     public byte[] pad(byte[] data, int ofs, int len)
249             throws BadPaddingException {
250         if (len > maxDataSize) {
251             throw new BadPaddingException("Data must be shorter than "
252                 + (maxDataSize + 1) + " bytes but received "
253                 + len + " bytes.");
254         }
255         switch (type) {
256         case PAD_NONE:
257             return RSACore.convert(data, ofs, len);
258         case PAD_BLOCKTYPE_1:
259         case PAD_BLOCKTYPE_2:
260             return padV15(data, ofs, len);
261         case PAD_OAEP_MGF1:
262             return padOAEP(data, ofs, len);
263         default:
264             throw new AssertionError();
265         }
266     }
267 
268     /**
269      * Unpad the padded block and return the data.
270      */
unpad(byte[] padded)271     public byte[] unpad(byte[] padded) throws BadPaddingException {
272         if (padded.length != paddedSize) {
273             throw new BadPaddingException("Decryption error." +
274                 "The padded array length (" + padded.length +
275                 ") is not the specified padded size (" + paddedSize + ")");
276         }
277         switch (type) {
278         case PAD_NONE:
279             return padded;
280         case PAD_BLOCKTYPE_1:
281         case PAD_BLOCKTYPE_2:
282             return unpadV15(padded);
283         case PAD_OAEP_MGF1:
284             return unpadOAEP(padded);
285         default:
286             throw new AssertionError();
287         }
288     }
289 
290     /**
291      * PKCS#1 v1.5 padding (blocktype 1 and 2).
292      */
padV15(byte[] data, int ofs, int len)293     private byte[] padV15(byte[] data, int ofs, int len) throws BadPaddingException {
294         byte[] padded = new byte[paddedSize];
295         System.arraycopy(data, ofs, padded, paddedSize - len, len);
296         int psSize = paddedSize - 3 - len;
297         int k = 0;
298         padded[k++] = 0;
299         padded[k++] = (byte)type;
300         if (type == PAD_BLOCKTYPE_1) {
301             // blocktype 1: all padding bytes are 0xff
302             while (psSize-- > 0) {
303                 padded[k++] = (byte)0xff;
304             }
305         } else {
306             // blocktype 2: padding bytes are random non-zero bytes
307             if (random == null) {
308                 random = JCAUtil.getSecureRandom();
309             }
310             // generate non-zero padding bytes
311             // use a buffer to reduce calls to SecureRandom
312             byte[] r = new byte[64];
313             int i = -1;
314             while (psSize-- > 0) {
315                 int b;
316                 do {
317                     if (i < 0) {
318                         random.nextBytes(r);
319                         i = r.length - 1;
320                     }
321                     b = r[i--] & 0xff;
322                 } while (b == 0);
323                 padded[k++] = (byte)b;
324             }
325         }
326         return padded;
327     }
328 
329     /**
330      * PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)).
331      *
332      * Note that we want to make it a constant-time operation
333      */
unpadV15(byte[] padded)334     private byte[] unpadV15(byte[] padded) throws BadPaddingException {
335         int k = 0;
336         boolean bp = false;
337 
338         if (padded[k++] != 0) {
339             bp = true;
340         }
341         if (padded[k++] != type) {
342             bp = true;
343         }
344         int p = 0;
345         while (k < padded.length) {
346             int b = padded[k++] & 0xff;
347             if ((b == 0) && (p == 0)) {
348                 p = k;
349             }
350             if ((k == padded.length) && (p == 0)) {
351                 bp = true;
352             }
353             if ((type == PAD_BLOCKTYPE_1) && (b != 0xff) &&
354                     (p == 0)) {
355                 bp = true;
356             }
357         }
358         int n = padded.length - p;
359         if (n > maxDataSize) {
360             bp = true;
361         }
362 
363         // copy useless padding array for a constant-time method
364         byte[] padding = new byte[p];
365         System.arraycopy(padded, 0, padding, 0, p);
366 
367         byte[] data = new byte[n];
368         System.arraycopy(padded, p, data, 0, n);
369 
370         BadPaddingException bpe = new BadPaddingException("Decryption error");
371 
372         if (bp) {
373             throw bpe;
374         } else {
375             return data;
376         }
377     }
378 
379     /**
380      * PKCS#1 v2.0 OAEP padding (MGF1).
381      * Paragraph references refer to PKCS#1 v2.1 (June 14, 2002)
382      */
padOAEP(byte[] M, int ofs, int len)383     private byte[] padOAEP(byte[] M, int ofs, int len) throws BadPaddingException {
384         if (random == null) {
385             random = JCAUtil.getSecureRandom();
386         }
387         int hLen = lHash.length;
388 
389         // 2.d: generate a random octet string seed of length hLen
390         // if necessary
391         byte[] seed = new byte[hLen];
392         random.nextBytes(seed);
393 
394         // buffer for encoded message EM
395         byte[] EM = new byte[paddedSize];
396 
397         // start and length of seed (as index into EM)
398         int seedStart = 1;
399         int seedLen = hLen;
400 
401         // copy seed into EM
402         System.arraycopy(seed, 0, EM, seedStart, seedLen);
403 
404         // start and length of data block DB in EM
405         // we place it inside of EM to reduce copying
406         int dbStart = hLen + 1;
407         int dbLen = EM.length - dbStart;
408 
409         // start of message M in EM
410         int mStart = paddedSize - len;
411 
412         // build DB
413         // 2.b: Concatenate lHash, PS, a single octet with hexadecimal value
414         // 0x01, and the message M to form a data block DB of length
415         // k - hLen -1 octets as DB = lHash || PS || 0x01 || M
416         // (note that PS is all zeros)
417         System.arraycopy(lHash, 0, EM, dbStart, hLen);
418         EM[mStart - 1] = 1;
419         System.arraycopy(M, ofs, EM, mStart, len);
420 
421         // produce maskedDB
422         mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
423 
424         // produce maskSeed
425         mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
426 
427         return EM;
428     }
429 
430     /**
431      * PKCS#1 v2.1 OAEP unpadding (MGF1).
432      */
unpadOAEP(byte[] padded)433     private byte[] unpadOAEP(byte[] padded) throws BadPaddingException {
434         byte[] EM = padded;
435         boolean bp = false;
436         int hLen = lHash.length;
437 
438         if (EM[0] != 0) {
439             bp = true;
440         }
441 
442         int seedStart = 1;
443         int seedLen = hLen;
444 
445         int dbStart = hLen + 1;
446         int dbLen = EM.length - dbStart;
447 
448         mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
449         mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
450 
451         // verify lHash == lHash'
452         for (int i = 0; i < hLen; i++) {
453             if (lHash[i] != EM[dbStart + i]) {
454                 bp = true;
455             }
456         }
457 
458         int padStart = dbStart + hLen;
459         int onePos = -1;
460 
461         for (int i = padStart; i < EM.length; i++) {
462             int value = EM[i];
463             if (onePos == -1) {
464                 if (value == 0x00) {
465                     // continue;
466                 } else if (value == 0x01) {
467                     onePos = i;
468                 } else {  // Anything other than {0,1} is bad.
469                     bp = true;
470                 }
471             }
472         }
473 
474         // We either ran off the rails or found something other than 0/1.
475         if (onePos == -1) {
476             bp = true;
477             onePos = EM.length - 1;  // Don't inadvertently return any data.
478         }
479 
480         int mStart = onePos + 1;
481 
482         // copy useless padding array for a constant-time method
483         byte [] tmp = new byte[mStart - padStart];
484         System.arraycopy(EM, padStart, tmp, 0, tmp.length);
485 
486         byte [] m = new byte[EM.length - mStart];
487         System.arraycopy(EM, mStart, m, 0, m.length);
488 
489         BadPaddingException bpe = new BadPaddingException("Decryption error");
490 
491         if (bp) {
492             throw bpe;
493         } else {
494             return m;
495         }
496     }
497 }
498