1 /*
   2  * Copyright (c) 2003, 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.  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 static final int PAD_BLOCKTYPE_1    = 1;
  86     // PKCS#1 v1.5 padding, blocktype 2 (encryption)
  87     public static final int PAD_BLOCKTYPE_2    = 2;
  88     // nopadding. Does not do anything, but allows simpler RSACipher code
  89     public static final int PAD_NONE           = 3;
  90     // PKCS#1 v2.1 OAEP padding
  91     public static final 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      */
 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      */
 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      */
 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
 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      */
 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      */
 234     public int getMaxDataSize() {
 235         return maxDataSize;
 236     }
 237 
 238     /**
 239      * Pad the data and return the padded block.
 240      */
 241     public byte[] pad(byte[] data, int ofs, int len)
 242             throws BadPaddingException {
 243         return pad(RSACore.convert(data, ofs, len));
 244     }
 245 
 246     /**
 247      * Pad the data and return the padded block.
 248      */
 249     public byte[] pad(byte[] data) throws BadPaddingException {
 250         if (data.length > maxDataSize) {
 251             throw new BadPaddingException("Data must be shorter than "
 252                 + (maxDataSize + 1) + " bytes but received "
 253                 + data.length + " bytes.");
 254         }
 255         switch (type) {
 256         case PAD_NONE:
 257             return data;
 258         case PAD_BLOCKTYPE_1:
 259         case PAD_BLOCKTYPE_2:
 260             return padV15(data);
 261         case PAD_OAEP_MGF1:
 262             return padOAEP(data);
 263         default:
 264             throw new AssertionError();
 265         }
 266     }
 267 
 268     /**
 269      * Unpad the padded block and return the data.
 270      */
 271     public byte[] unpad(byte[] padded, int ofs, int len)
 272             throws BadPaddingException {
 273         return unpad(RSACore.convert(padded, ofs, len));
 274     }
 275 
 276     /**
 277      * Unpad the padded block and return the data.
 278      */
 279     public byte[] unpad(byte[] padded) throws BadPaddingException {
 280         if (padded.length != paddedSize) {
 281             throw new BadPaddingException("Decryption error." +
 282                 "The padded array length (" + padded.length +
 283                 ") is not the specified padded size (" + paddedSize + ")");
 284         }
 285         switch (type) {
 286         case PAD_NONE:
 287             return padded;
 288         case PAD_BLOCKTYPE_1:
 289         case PAD_BLOCKTYPE_2:
 290             return unpadV15(padded);
 291         case PAD_OAEP_MGF1:
 292             return unpadOAEP(padded);
 293         default:
 294             throw new AssertionError();
 295         }
 296     }
 297 
 298     /**
 299      * PKCS#1 v1.5 padding (blocktype 1 and 2).
 300      */
 301     private byte[] padV15(byte[] data) throws BadPaddingException {
 302         byte[] padded = new byte[paddedSize];
 303         System.arraycopy(data, 0, padded, paddedSize - data.length,
 304             data.length);
 305         int psSize = paddedSize - 3 - data.length;
 306         int k = 0;
 307         padded[k++] = 0;
 308         padded[k++] = (byte)type;
 309         if (type == PAD_BLOCKTYPE_1) {
 310             // blocktype 1: all padding bytes are 0xff
 311             while (psSize-- > 0) {
 312                 padded[k++] = (byte)0xff;
 313             }
 314         } else {
 315             // blocktype 2: padding bytes are random non-zero bytes
 316             if (random == null) {
 317                 random = JCAUtil.getSecureRandom();
 318             }
 319             // generate non-zero padding bytes
 320             // use a buffer to reduce calls to SecureRandom
 321             while (psSize > 0) {
 322                 // extra bytes to avoid zero bytes,
 323                 // number of zero bytes <= 4 in 98% cases
 324                 byte[] r = new byte[psSize + 4];
 325                 random.nextBytes(r);
 326                 for (int i = 0; i < r.length && psSize > 0; i++) {
 327                     if (r[i] != 0) {
 328                         padded[k++] = r[i];
 329                         psSize--;
 330                     }
 331                 }
 332             }
 333         }
 334         return padded;
 335     }
 336 
 337     /**
 338      * PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)).
 339      *
 340      * Note that we want to make it a constant-time operation
 341      */
 342     private byte[] unpadV15(byte[] padded) throws BadPaddingException {
 343         int k = 0;
 344         boolean bp = false;
 345 
 346         if (padded[k++] != 0) {
 347             bp = true;
 348         }
 349         if (padded[k++] != type) {
 350             bp = true;
 351         }
 352         int p = 0;
 353         while (k < padded.length) {
 354             int b = padded[k++] & 0xff;
 355             if ((b == 0) && (p == 0)) {
 356                 p = k;
 357             }
 358             if ((k == padded.length) && (p == 0)) {
 359                 bp = true;
 360             }
 361             if ((type == PAD_BLOCKTYPE_1) && (b != 0xff) &&
 362                     (p == 0)) {
 363                 bp = true;
 364             }
 365         }
 366         int n = padded.length - p;
 367         if (n > maxDataSize) {
 368             bp = true;
 369         }
 370 
 371         // copy useless padding array for a constant-time method
 372         byte[] padding = new byte[p];
 373         System.arraycopy(padded, 0, padding, 0, p);
 374 
 375         byte[] data = new byte[n];
 376         System.arraycopy(padded, p, data, 0, n);
 377 
 378         BadPaddingException bpe = new BadPaddingException("Decryption error");
 379 
 380         if (bp) {
 381             throw bpe;
 382         } else {
 383             return data;
 384         }
 385     }
 386 
 387     /**
 388      * PKCS#1 v2.0 OAEP padding (MGF1).
 389      * Paragraph references refer to PKCS#1 v2.1 (June 14, 2002)
 390      */
 391     private byte[] padOAEP(byte[] M) throws BadPaddingException {
 392         if (random == null) {
 393             random = JCAUtil.getSecureRandom();
 394         }
 395         int hLen = lHash.length;
 396 
 397         // 2.d: generate a random octet string seed of length hLen
 398         // if necessary
 399         byte[] seed = new byte[hLen];
 400         random.nextBytes(seed);
 401 
 402         // buffer for encoded message EM
 403         byte[] EM = new byte[paddedSize];
 404 
 405         // start and length of seed (as index into EM)
 406         int seedStart = 1;
 407         int seedLen = hLen;
 408 
 409         // copy seed into EM
 410         System.arraycopy(seed, 0, EM, seedStart, seedLen);
 411 
 412         // start and length of data block DB in EM
 413         // we place it inside of EM to reduce copying
 414         int dbStart = hLen + 1;
 415         int dbLen = EM.length - dbStart;
 416 
 417         // start of message M in EM
 418         int mStart = paddedSize - M.length;
 419 
 420         // build DB
 421         // 2.b: Concatenate lHash, PS, a single octet with hexadecimal value
 422         // 0x01, and the message M to form a data block DB of length
 423         // k - hLen -1 octets as DB = lHash || PS || 0x01 || M
 424         // (note that PS is all zeros)
 425         System.arraycopy(lHash, 0, EM, dbStart, hLen);
 426         EM[mStart - 1] = 1;
 427         System.arraycopy(M, 0, EM, mStart, M.length);
 428 
 429         // produce maskedDB
 430         mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
 431 
 432         // produce maskSeed
 433         mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
 434 
 435         return EM;
 436     }
 437 
 438     /**
 439      * PKCS#1 v2.1 OAEP unpadding (MGF1).
 440      */
 441     private byte[] unpadOAEP(byte[] padded) throws BadPaddingException {
 442         byte[] EM = padded;
 443         boolean bp = false;
 444         int hLen = lHash.length;
 445 
 446         if (EM[0] != 0) {
 447             bp = true;
 448         }
 449 
 450         int seedStart = 1;
 451         int seedLen = hLen;
 452 
 453         int dbStart = hLen + 1;
 454         int dbLen = EM.length - dbStart;
 455 
 456         mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
 457         mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
 458 
 459         // verify lHash == lHash'
 460         for (int i = 0; i < hLen; i++) {
 461             if (lHash[i] != EM[dbStart + i]) {
 462                 bp = true;
 463             }
 464         }
 465 
 466         int padStart = dbStart + hLen;
 467         int onePos = -1;
 468 
 469         for (int i = padStart; i < EM.length; i++) {
 470             int value = EM[i];
 471             if (onePos == -1) {
 472                 if (value == 0x00) {
 473                     // continue;
 474                 } else if (value == 0x01) {
 475                     onePos = i;
 476                 } else {  // Anything other than {0,1} is bad.
 477                     bp = true;
 478                 }
 479             }
 480         }
 481 
 482         // We either ran off the rails or found something other than 0/1.
 483         if (onePos == -1) {
 484             bp = true;
 485             onePos = EM.length - 1;  // Don't inadvertently return any data.
 486         }
 487 
 488         int mStart = onePos + 1;
 489 
 490         // copy useless padding array for a constant-time method
 491         byte [] tmp = new byte[mStart - padStart];
 492         System.arraycopy(EM, padStart, tmp, 0, tmp.length);
 493 
 494         byte [] m = new byte[EM.length - mStart];
 495         System.arraycopy(EM, mStart, m, 0, m.length);
 496 
 497         BadPaddingException bpe = new BadPaddingException("Decryption error");
 498 
 499         if (bp) {
 500             throw bpe;
 501         } else {
 502             return m;
 503         }
 504     }
 505 }