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