1 /* |
1 /* |
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
37 import sun.security.jca.JCAUtil; |
37 import sun.security.jca.JCAUtil; |
38 |
38 |
39 /** |
39 /** |
40 * RSA padding and unpadding. |
40 * RSA padding and unpadding. |
41 * |
41 * |
42 * The various PKCS#1 versions can be found in the EMC/RSA Labs |
42 * The various PKCS#1 versions can be found in the IETF RFCs |
43 * web site, which is currently: |
43 * tracking the corresponding PKCS#1 standards. |
44 * |
44 * |
45 * http://www.emc.com/emc-plus/rsa-labs/index.htm |
45 * RFC 2313: PKCS#1 v1.5 |
46 * |
46 * RFC 2437: PKCS#1 v2.0 |
47 * or in the IETF RFCs derived from the above PKCS#1 standards. |
47 * RFC 3447: PKCS#1 v2.1 |
48 * |
48 * RFC 8017: PKCS#1 v2.2 |
49 * RFC 2313: v1.5 |
|
50 * RFC 2437: v2.0 |
|
51 * RFC 3447: v2.1 |
|
52 * |
49 * |
53 * The format of PKCS#1 v1.5 padding is: |
50 * The format of PKCS#1 v1.5 padding is: |
54 * |
51 * |
55 * 0x00 | BT | PS...PS | 0x00 | data...data |
52 * 0x00 | BT | PS...PS | 0x00 | data...data |
56 * |
53 * |
103 private SecureRandom random; |
100 private SecureRandom random; |
104 |
101 |
105 // maximum size of the data |
102 // maximum size of the data |
106 private final int maxDataSize; |
103 private final int maxDataSize; |
107 |
104 |
108 // OAEP: main messagedigest |
105 // OAEP: main message digest |
109 private MessageDigest md; |
106 private MessageDigest md; |
110 |
107 |
111 // OAEP: message digest for MGF1 |
108 // OAEP: MGF1 |
112 private MessageDigest mgfMd; |
109 private MGF1 mgf; |
113 |
110 |
114 // OAEP: value of digest of data (user-supplied or zero-length) using md |
111 // OAEP: value of digest of data (user-supplied or zero-length) using md |
115 private byte[] lHash; |
112 private byte[] lHash; |
116 |
113 |
117 /** |
114 /** |
162 case PAD_NONE: |
159 case PAD_NONE: |
163 maxDataSize = paddedSize; |
160 maxDataSize = paddedSize; |
164 break; |
161 break; |
165 case PAD_OAEP_MGF1: |
162 case PAD_OAEP_MGF1: |
166 String mdName = "SHA-1"; |
163 String mdName = "SHA-1"; |
167 String mgfMdName = "SHA-1"; |
164 String mgfMdName = mdName; |
168 byte[] digestInput = null; |
165 byte[] digestInput = null; |
169 try { |
166 try { |
170 if (spec != null) { |
167 if (spec != null) { |
171 mdName = spec.getDigestAlgorithm(); |
168 mdName = spec.getDigestAlgorithm(); |
172 String mgfName = spec.getMGFAlgorithm(); |
169 String mgfName = spec.getMGFAlgorithm(); |
183 ("Unsupported pSource algo: " + pSrcAlgo); |
180 ("Unsupported pSource algo: " + pSrcAlgo); |
184 } |
181 } |
185 digestInput = ((PSource.PSpecified) pSrc).getValue(); |
182 digestInput = ((PSource.PSpecified) pSrc).getValue(); |
186 } |
183 } |
187 md = MessageDigest.getInstance(mdName); |
184 md = MessageDigest.getInstance(mdName); |
188 mgfMd = MessageDigest.getInstance(mgfMdName); |
185 mgf = new MGF1(mgfMdName); |
189 } catch (NoSuchAlgorithmException e) { |
186 } catch (NoSuchAlgorithmException e) { |
190 throw new InvalidKeyException |
187 throw new InvalidKeyException("Digest not available", e); |
191 ("Digest " + mdName + " not available", e); |
|
192 } |
188 } |
193 lHash = getInitialHash(md, digestInput); |
189 lHash = getInitialHash(md, digestInput); |
194 int digestLen = lHash.length; |
190 int digestLen = lHash.length; |
195 maxDataSize = paddedSize - 2 - 2 * digestLen; |
191 maxDataSize = paddedSize - 2 - 2 * digestLen; |
196 if (maxDataSize <= 0) { |
192 if (maxDataSize <= 0) { |
197 throw new InvalidKeyException |
193 throw new InvalidKeyException |
198 ("Key is too short for encryption using OAEPPadding" + |
194 ("Key is too short for encryption using OAEPPadding" + |
199 " with " + mdName + " and MGF1" + mgfMdName); |
195 " with " + mdName + " and " + mgf.getName()); |
200 } |
196 } |
201 break; |
197 break; |
202 default: |
198 default: |
203 throw new InvalidKeyException("Invalid padding: " + type); |
199 throw new InvalidKeyException("Invalid padding: " + type); |
204 } |
200 } |
429 System.arraycopy(lHash, 0, EM, dbStart, hLen); |
425 System.arraycopy(lHash, 0, EM, dbStart, hLen); |
430 EM[mStart - 1] = 1; |
426 EM[mStart - 1] = 1; |
431 System.arraycopy(M, 0, EM, mStart, M.length); |
427 System.arraycopy(M, 0, EM, mStart, M.length); |
432 |
428 |
433 // produce maskedDB |
429 // produce maskedDB |
434 mgf1(EM, seedStart, seedLen, EM, dbStart, dbLen); |
430 mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart); |
435 |
431 |
436 // produce maskSeed |
432 // produce maskSeed |
437 mgf1(EM, dbStart, dbLen, EM, seedStart, seedLen); |
433 mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart); |
438 |
434 |
439 return EM; |
435 return EM; |
440 } |
436 } |
441 |
437 |
442 /** |
438 /** |
455 int seedLen = hLen; |
451 int seedLen = hLen; |
456 |
452 |
457 int dbStart = hLen + 1; |
453 int dbStart = hLen + 1; |
458 int dbLen = EM.length - dbStart; |
454 int dbLen = EM.length - dbStart; |
459 |
455 |
460 mgf1(EM, dbStart, dbLen, EM, seedStart, seedLen); |
456 mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart); |
461 mgf1(EM, seedStart, seedLen, EM, dbStart, dbLen); |
457 mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart); |
462 |
458 |
463 // verify lHash == lHash' |
459 // verify lHash == lHash' |
464 for (int i = 0; i < hLen; i++) { |
460 for (int i = 0; i < hLen; i++) { |
465 if (lHash[i] != EM[dbStart + i]) { |
461 if (lHash[i] != EM[dbStart + i]) { |
466 bp = true; |
462 bp = true; |
504 throw bpe; |
500 throw bpe; |
505 } else { |
501 } else { |
506 return m; |
502 return m; |
507 } |
503 } |
508 } |
504 } |
509 |
|
510 /** |
|
511 * Compute MGF1 using mgfMD as the message digest. |
|
512 * Note that we combine MGF1 with the XOR operation to reduce data |
|
513 * copying. |
|
514 * |
|
515 * We generate maskLen bytes of MGF1 from the seed and XOR it into |
|
516 * out[] starting at outOfs; |
|
517 */ |
|
518 private void mgf1(byte[] seed, int seedOfs, int seedLen, |
|
519 byte[] out, int outOfs, int maskLen) throws BadPaddingException { |
|
520 byte[] C = new byte[4]; // 32 bit counter |
|
521 byte[] digest = new byte[mgfMd.getDigestLength()]; |
|
522 while (maskLen > 0) { |
|
523 mgfMd.update(seed, seedOfs, seedLen); |
|
524 mgfMd.update(C); |
|
525 try { |
|
526 mgfMd.digest(digest, 0, digest.length); |
|
527 } catch (DigestException e) { |
|
528 // should never happen |
|
529 throw new BadPaddingException(e.toString()); |
|
530 } |
|
531 for (int i = 0; (i < digest.length) && (maskLen > 0); maskLen--) { |
|
532 out[outOfs++] ^= digest[i++]; |
|
533 } |
|
534 if (maskLen > 0) { |
|
535 // increment counter |
|
536 for (int i = C.length - 1; (++C[i] == 0) && (i > 0); i--) { |
|
537 // empty |
|
538 } |
|
539 } |
|
540 } |
|
541 } |
|
542 } |
505 } |