History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/rsa/RSAPadding.java (1 of 18352 files). Show all

Unified · Split

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