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
26package com.sun.crypto.provider;
27
28import java.io.UnsupportedEncodingException;
29import java.math.BigInteger;
30import java.security.*;
31import java.security.spec.*;
32import java.util.Arrays;
33import javax.crypto.*;
34import 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 */
46final 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}