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/com/sun/crypto/provider/PKCS12PBECipherCore.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/crypto/provider/PKCS12PBECipherCore.java+521−0
@@ -0,0 +1,521 @@
1+/*
2+ * Copyright (c) 2003, 2010, 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 com.sun.crypto.provider;
27+
28+import java.io.UnsupportedEncodingException;
29+import java.math.BigInteger;
30+import java.security.*;
31+import java.security.spec.*;
32+import java.util.Arrays;
33+import javax.crypto.*;
34+import javax.crypto.spec.*;
35+
36+/**
37+ * This class implements password-base encryption algorithm with
38+ * SHA1 digest and the following Ciphers in CBC mode
39+ * - DESede cipher and
40+ * - RC2 Cipher with 40-bit effective key length
41+ * as defined by PKCS #12 version 1.0 standard.
42+ *
43+ * @author Valerie Peng
44+ * @see javax.crypto.CipherSpi
45+ */
46+final class PKCS12PBECipherCore {
47+ private CipherCore cipher;
48+ private int blockSize;
49+ private int keySize;
50+ private String algo = null;
51+ private byte[] salt = null;
52+ private int iCount = 0;
53+
54+ private static final int DEFAULT_SALT_LENGTH = 20;
55+ private static final int DEFAULT_COUNT = 1024;
56+
57+ static final int CIPHER_KEY = 1;
58+ static final int CIPHER_IV = 2;
59+ static final int MAC_KEY = 3;
60+
61+ static byte[] derive(char[] chars, byte[] salt,
62+ int ic, int n, int type) {
63+ // Add in trailing NULL terminator.
64+ int length = chars.length*2;
65+ if (length != 0) {
66+ length += 2;
67+ }
68+ byte[] passwd = new byte[length];
69+ for (int i = 0, j = 0; i < chars.length; i++, j+=2) {
70+ passwd[j] = (byte) ((chars[i] >>> 8) & 0xFF);
71+ passwd[j+1] = (byte) (chars[i] & 0xFF);
72+ }
73+ int v = 512 / 8;
74+ int u = 160 / 8;
75+ int c = roundup(n, u) / u;
76+ byte[] D = new byte[v];
77+ int s = roundup(salt.length, v);
78+ int p = roundup(passwd.length, v);
79+ byte[] I = new byte[s + p];
80+ byte[] key = new byte[n];
81+
82+ Arrays.fill(D, (byte)type);
83+ concat(salt, I, 0, s);
84+ concat(passwd, I, s, p);
85+
86+ try {
87+ MessageDigest sha = MessageDigest.getInstance("SHA1");
88+ byte[] Ai;
89+ byte[] B = new byte[v];
90+ byte[] tmp = new byte[v];
91+
92+ int i = 0;
93+ for (; ; i++, n -= u) {
94+ sha.update(D);
95+ sha.update(I);
96+ Ai = sha.digest();
97+ for (int r = 1; r < ic; r++)
98+ Ai = sha.digest(Ai);
99+ System.arraycopy(Ai, 0, key, u * i, Math.min(n, u));
100+ if (i + 1 == c)
101+ break;
102+ concat(Ai, B, 0, B.length);
103+ BigInteger B1;
104+ B1 = new BigInteger(1, B).add(BigInteger.ONE);
105+
106+ for (int j = 0; j < I.length; j += v) {
107+ BigInteger Ij;
108+ int trunc;
109+
110+ if (tmp.length != v)
111+ tmp = new byte[v];
112+ System.arraycopy(I, j, tmp, 0, v);
113+ Ij = new BigInteger(1, tmp);
114+ Ij = Ij.add(B1);
115+ tmp = Ij.toByteArray();
116+ trunc = tmp.length - v;
117+ if (trunc >= 0) {
118+ System.arraycopy(tmp, trunc, I, j, v);
119+ } else if (trunc < 0) {
120+ Arrays.fill(I, j, j + (-trunc), (byte)0);
121+ System.arraycopy(tmp, 0, I, j + (-trunc), tmp.length);
122+ }
123+ }
124+ }
125+ } catch (Exception e) {
126+ throw new RuntimeException("internal error: " + e);
127+ }
128+ return key;
129+ }
130+
131+ private static int roundup(int x, int y) {
132+ return ((x + (y - 1)) / y) * y;
133+ }
134+
135+ private static void concat(byte[] src, byte[] dst, int start, int len) {
136+ int loop = len / src.length;
137+ int off, i;
138+ for (i = 0, off = 0; i < loop; i++, off += src.length)
139+ System.arraycopy(src, 0, dst, off + start, src.length);
140+ System.arraycopy(src, 0, dst, off + start, len - off);
141+ }
142+
143+ PKCS12PBECipherCore(String symmCipherAlg, int defKeySize)
144+ throws NoSuchAlgorithmException {
145+ algo = symmCipherAlg;
146+ SymmetricCipher symmCipher = null;
147+ if (algo.equals("DESede")) {
148+ symmCipher = new DESedeCrypt();
149+ } else if (algo.equals("RC2")) {
150+ symmCipher = new RC2Crypt();
151+ } else {
152+ throw new NoSuchAlgorithmException("No Cipher implementation " +
153+ "for PBEWithSHA1And" + algo);
154+ }
155+ blockSize = symmCipher.getBlockSize();
156+ cipher = new CipherCore(symmCipher, blockSize);
157+ cipher.setMode("CBC");
158+ try {
159+ cipher.setPadding("PKCS5Padding");
160+ } catch (NoSuchPaddingException nspe) {
161+ // should not happen
162+ }
163+ keySize = defKeySize;
164+ }
165+
166+ void implSetMode(String mode) throws NoSuchAlgorithmException {
167+ if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
168+ throw new NoSuchAlgorithmException("Invalid cipher mode: "
169+ + mode);
170+ }
171+ }
172+
173+ void implSetPadding(String padding) throws NoSuchPaddingException {
174+ if ((padding != null) &&
175+ (!padding.equalsIgnoreCase("PKCS5Padding"))) {
176+ throw new NoSuchPaddingException("Invalid padding scheme: " +
177+ padding);
178+ }
179+ }
180+
181+ int implGetBlockSize() {
182+ return blockSize;
183+ }
184+
185+ int implGetOutputSize(int inLen) {
186+ return cipher.getOutputSize(inLen);
187+ }
188+
189+ byte[] implGetIV() {
190+ return cipher.getIV();
191+ }
192+
193+ AlgorithmParameters implGetParameters() {
194+ AlgorithmParameters params = null;
195+ if (salt == null) {
196+ // Cipher is not initialized with parameters;
197+ // follow the recommendation in PKCS12 v1.0
198+ // section B.4 to generate salt and iCount.
199+ salt = new byte[DEFAULT_SALT_LENGTH];
200+ SunJCE.RANDOM.nextBytes(salt);
201+ iCount = DEFAULT_COUNT;
202+ }
203+ PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
204+ try {
205+ params = AlgorithmParameters.getInstance("PBEWithSHA1And" +
206+ (algo.equalsIgnoreCase("RC2")?"RC2_40":algo), "SunJCE");
207+ } catch (GeneralSecurityException gse) {
208+ // should never happen
209+ throw new RuntimeException(
210+ "SunJCE provider is not configured properly");
211+ }
212+ try {
213+ params.init(pbeSpec);
214+ } catch (InvalidParameterSpecException ipse) {
215+ // should never happen
216+ throw new RuntimeException("PBEParameterSpec not supported");
217+ }
218+ return params;
219+ }
220+
221+ void implInit(int opmode, Key key, AlgorithmParameterSpec params,
222+ SecureRandom random) throws InvalidKeyException,
223+ InvalidAlgorithmParameterException {
224+ char[] passwdChars = null;
225+ salt = null;
226+ iCount = 0;
227+ if (key instanceof javax.crypto.interfaces.PBEKey) {
228+ javax.crypto.interfaces.PBEKey pbeKey =
229+ (javax.crypto.interfaces.PBEKey) key;
230+ passwdChars = pbeKey.getPassword();
231+ salt = pbeKey.getSalt(); // maybe null if unspecified
232+ iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
233+ } else if (key instanceof SecretKey) {
234+ byte[] passwdBytes = key.getEncoded();
235+ if ((passwdBytes == null) ||
236+ !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
237+ throw new InvalidKeyException("Missing password");
238+ }
239+ passwdChars = new char[passwdBytes.length];
240+ for (int i=0; i<passwdChars.length; i++) {
241+ passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
242+ }
243+ } else {
244+ throw new InvalidKeyException("SecretKey of PBE type required");
245+ }
246+
247+ if (((opmode == Cipher.DECRYPT_MODE) ||
248+ (opmode == Cipher.UNWRAP_MODE)) &&
249+ ((params == null) && ((salt == null) || (iCount == 0)))) {
250+ throw new InvalidAlgorithmParameterException
251+ ("Parameters missing");
252+ }
253+
254+ if (params == null) {
255+ // generate default for salt and iteration count if necessary
256+ if (salt == null) {
257+ salt = new byte[DEFAULT_SALT_LENGTH];
258+ if (random != null) {
259+ random.nextBytes(salt);
260+ } else {
261+ SunJCE.RANDOM.nextBytes(salt);
262+ }
263+ }
264+ if (iCount == 0) iCount = DEFAULT_COUNT;
265+ } else if (!(params instanceof PBEParameterSpec)) {
266+ throw new InvalidAlgorithmParameterException
267+ ("PBEParameterSpec type required");
268+ } else {
269+ PBEParameterSpec pbeParams = (PBEParameterSpec) params;
270+ // make sure the parameter values are consistent
271+ if (salt != null) {
272+ if (!Arrays.equals(salt, pbeParams.getSalt())) {
273+ throw new InvalidAlgorithmParameterException
274+ ("Inconsistent value of salt between key and params");
275+ }
276+ } else {
277+ salt = pbeParams.getSalt();
278+ }
279+ if (iCount != 0) {
280+ if (iCount != pbeParams.getIterationCount()) {
281+ throw new InvalidAlgorithmParameterException
282+ ("Different iteration count between key and params");
283+ }
284+ } else {
285+ iCount = pbeParams.getIterationCount();
286+ }
287+ }
288+ // salt is recommended to be ideally as long as the output
289+ // of the hash function. However, it may be too strict to
290+ // force this; so instead, we'll just require the minimum
291+ // salt length to be 8-byte which is what PKCS#5 recommends
292+ // and openssl does.
293+ if (salt.length < 8) {
294+ throw new InvalidAlgorithmParameterException
295+ ("Salt must be at least 8 bytes long");
296+ }
297+ if (iCount <= 0) {
298+ throw new InvalidAlgorithmParameterException
299+ ("IterationCount must be a positive number");
300+ }
301+ byte[] derivedKey = derive(passwdChars, salt, iCount,
302+ keySize, CIPHER_KEY);
303+ SecretKey cipherKey = new SecretKeySpec(derivedKey, algo);
304+ byte[] derivedIv = derive(passwdChars, salt, iCount, 8,
305+ CIPHER_IV);
306+ IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8);
307+
308+ // initialize the underlying cipher
309+ cipher.init(opmode, cipherKey, ivSpec, random);
310+ }
311+
312+ void implInit(int opmode, Key key, AlgorithmParameters params,
313+ SecureRandom random)
314+ throws InvalidKeyException, InvalidAlgorithmParameterException {
315+ AlgorithmParameterSpec paramSpec = null;
316+ if (params != null) {
317+ try {
318+ paramSpec = params.getParameterSpec(PBEParameterSpec.class);
319+ } catch (InvalidParameterSpecException ipse) {
320+ throw new InvalidAlgorithmParameterException(
321+ "requires PBE parameters");
322+ }
323+ }
324+ implInit(opmode, key, paramSpec, random);
325+ }
326+
327+ void implInit(int opmode, Key key, SecureRandom random)
328+ throws InvalidKeyException {
329+ try {
330+ implInit(opmode, key, (AlgorithmParameterSpec) null, random);
331+ } catch (InvalidAlgorithmParameterException iape) {
332+ throw new InvalidKeyException("requires PBE parameters");
333+ }
334+ }
335+
336+ byte[] implUpdate(byte[] in, int inOff, int inLen) {
337+ return cipher.update(in, inOff, inLen);
338+ }
339+
340+ int implUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)
341+ throws ShortBufferException {
342+ return cipher.update(in, inOff, inLen, out, outOff);
343+ }
344+
345+ byte[] implDoFinal(byte[] in, int inOff, int inLen)
346+ throws IllegalBlockSizeException, BadPaddingException {
347+ return cipher.doFinal(in, inOff, inLen);
348+ }
349+
350+ int implDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
351+ throws ShortBufferException, IllegalBlockSizeException,
352+ BadPaddingException {
353+ return cipher.doFinal(in, inOff, inLen, out, outOff);
354+ }
355+
356+ int implGetKeySize(Key key) throws InvalidKeyException {
357+ return keySize;
358+ }
359+
360+ byte[] implWrap(Key key) throws IllegalBlockSizeException,
361+ InvalidKeyException {
362+ return cipher.wrap(key);
363+ }
364+
365+ Key implUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
366+ int wrappedKeyType)
367+ throws InvalidKeyException, NoSuchAlgorithmException {
368+ return cipher.unwrap(wrappedKey, wrappedKeyAlgorithm,
369+ wrappedKeyType);
370+ }
371+
372+ public static final class PBEWithSHA1AndDESede extends CipherSpi {
373+ private final PKCS12PBECipherCore core;
374+ public PBEWithSHA1AndDESede() throws NoSuchAlgorithmException {
375+ core = new PKCS12PBECipherCore("DESede", 24);
376+ }
377+ protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
378+ throws IllegalBlockSizeException, BadPaddingException {
379+ return core.implDoFinal(in, inOff, inLen);
380+ }
381+ protected int engineDoFinal(byte[] in, int inOff, int inLen,
382+ byte[] out, int outOff)
383+ throws ShortBufferException, IllegalBlockSizeException,
384+ BadPaddingException {
385+ return core.implDoFinal(in, inOff, inLen, out, outOff);
386+ }
387+ protected int engineGetBlockSize() {
388+ return core.implGetBlockSize();
389+ }
390+ protected byte[] engineGetIV() {
391+ return core.implGetIV();
392+ }
393+ protected int engineGetKeySize(Key key) throws InvalidKeyException {
394+ return core.implGetKeySize(key);
395+ }
396+ protected int engineGetOutputSize(int inLen) {
397+ return core.implGetOutputSize(inLen);
398+ }
399+ protected AlgorithmParameters engineGetParameters() {
400+ return core.implGetParameters();
401+ }
402+ protected void engineInit(int opmode, Key key,
403+ AlgorithmParameterSpec params,
404+ SecureRandom random)
405+ throws InvalidKeyException, InvalidAlgorithmParameterException {
406+ core.implInit(opmode, key, params, random);
407+ }
408+ protected void engineInit(int opmode, Key key,
409+ AlgorithmParameters params,
410+ SecureRandom random)
411+ throws InvalidKeyException, InvalidAlgorithmParameterException {
412+ core.implInit(opmode, key, params, random);
413+ }
414+ protected void engineInit(int opmode, Key key, SecureRandom random)
415+ throws InvalidKeyException {
416+ core.implInit(opmode, key, random);
417+ }
418+ protected void engineSetMode(String mode)
419+ throws NoSuchAlgorithmException {
420+ core.implSetMode(mode);
421+ }
422+ protected void engineSetPadding(String paddingScheme)
423+ throws NoSuchPaddingException {
424+ core.implSetPadding(paddingScheme);
425+ }
426+ protected Key engineUnwrap(byte[] wrappedKey,
427+ String wrappedKeyAlgorithm,
428+ int wrappedKeyType)
429+ throws InvalidKeyException, NoSuchAlgorithmException {
430+ return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
431+ wrappedKeyType);
432+ }
433+ protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
434+ return core.implUpdate(in, inOff, inLen);
435+ }
436+ protected int engineUpdate(byte[] in, int inOff, int inLen,
437+ byte[] out, int outOff)
438+ throws ShortBufferException {
439+ return core.implUpdate(in, inOff, inLen, out, outOff);
440+ }
441+ protected byte[] engineWrap(Key key)
442+ throws IllegalBlockSizeException, InvalidKeyException {
443+ return core.implWrap(key);
444+ }
445+ }
446+
447+ public static final class PBEWithSHA1AndRC2_40 extends CipherSpi {
448+ private final PKCS12PBECipherCore core;
449+ public PBEWithSHA1AndRC2_40() throws NoSuchAlgorithmException {
450+ core = new PKCS12PBECipherCore("RC2", 5);
451+ }
452+ protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
453+ throws IllegalBlockSizeException, BadPaddingException {
454+ return core.implDoFinal(in, inOff, inLen);
455+ }
456+ protected int engineDoFinal(byte[] in, int inOff, int inLen,
457+ byte[] out, int outOff)
458+ throws ShortBufferException, IllegalBlockSizeException,
459+ BadPaddingException {
460+ return core.implDoFinal(in, inOff, inLen, out, outOff);
461+ }
462+ protected int engineGetBlockSize() {
463+ return core.implGetBlockSize();
464+ }
465+ protected byte[] engineGetIV() {
466+ return core.implGetIV();
467+ }
468+ protected int engineGetKeySize(Key key) throws InvalidKeyException {
469+ return core.implGetKeySize(key);
470+ }
471+ protected int engineGetOutputSize(int inLen) {
472+ return core.implGetOutputSize(inLen);
473+ }
474+ protected AlgorithmParameters engineGetParameters() {
475+ return core.implGetParameters();
476+ }
477+ protected void engineInit(int opmode, Key key,
478+ AlgorithmParameterSpec params,
479+ SecureRandom random)
480+ throws InvalidKeyException, InvalidAlgorithmParameterException {
481+ core.implInit(opmode, key, params, random);
482+ }
483+ protected void engineInit(int opmode, Key key,
484+ AlgorithmParameters params,
485+ SecureRandom random)
486+ throws InvalidKeyException, InvalidAlgorithmParameterException {
487+ core.implInit(opmode, key, params, random);
488+ }
489+ protected void engineInit(int opmode, Key key, SecureRandom random)
490+ throws InvalidKeyException {
491+ core.implInit(opmode, key, random);
492+ }
493+ protected void engineSetMode(String mode)
494+ throws NoSuchAlgorithmException {
495+ core.implSetMode(mode);
496+ }
497+ protected void engineSetPadding(String paddingScheme)
498+ throws NoSuchPaddingException {
499+ core.implSetPadding(paddingScheme);
500+ }
501+ protected Key engineUnwrap(byte[] wrappedKey,
502+ String wrappedKeyAlgorithm,
503+ int wrappedKeyType)
504+ throws InvalidKeyException, NoSuchAlgorithmException {
505+ return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
506+ wrappedKeyType);
507+ }
508+ protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
509+ return core.implUpdate(in, inOff, inLen);
510+ }
511+ protected int engineUpdate(byte[] in, int inOff, int inLen,
512+ byte[] out, int outOff)
513+ throws ShortBufferException {
514+ return core.implUpdate(in, inOff, inLen, out, outOff);
515+ }
516+ protected byte[] engineWrap(Key key)
517+ throws IllegalBlockSizeException, InvalidKeyException {
518+ return core.implWrap(key);
519+ }
520+ }
521+}