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/PBKDF2KeyImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/crypto/provider/PBKDF2KeyImpl.java+282−0
@@ -0,0 +1,282 @@
1/*
2 * Copyright (c) 2005, 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.ObjectStreamException;
29import java.nio.ByteBuffer;
30import java.nio.CharBuffer;
31import java.nio.charset.Charset;
32import java.util.Arrays;
33import java.security.KeyRep;
34import java.security.GeneralSecurityException;
35import java.security.NoSuchAlgorithmException;
36import java.security.NoSuchProviderException;
37import java.security.spec.InvalidKeySpecException;
38import javax.crypto.Mac;
39import javax.crypto.SecretKey;
40import javax.crypto.spec.PBEKeySpec;
41
42/**
43 * This class represents a PBE key derived using PBKDF2 defined
44 * in PKCS#5 v2.0. meaning that
45 * 1) the password must consist of characters which will be converted
46 * to bytes using UTF-8 character encoding.
47 * 2) salt, iteration count, and to be derived key length are supplied
48 *
49 * @author Valerie Peng
50 *
51 */
52final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
53
54 static final long serialVersionUID = -2234868909660948157L;
55
56 private char[] passwd;
57 private byte[] salt;
58 private int iterCount;
59 private byte[] key;
60
61 private Mac prf;
62
63 private static byte[] getPasswordBytes(char[] passwd) {
64 Charset utf8 = Charset.forName("UTF-8");
65 CharBuffer cb = CharBuffer.wrap(passwd);
66 ByteBuffer bb = utf8.encode(cb);
67
68 int len = bb.limit();
69 byte[] passwdBytes = new byte[len];
70 bb.get(passwdBytes, 0, len);
71
72 return passwdBytes;
73 }
74
75 /**
76 * Creates a PBE key from a given PBE key specification.
77 *
78 * @param key the given PBE key specification
79 */
80 PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
81 throws InvalidKeySpecException {
82 char[] passwd = keySpec.getPassword();
83 if (passwd == null) {
84 // Should allow an empty password.
85 this.passwd = new char[0];
86 } else {
87 this.passwd = passwd.clone();
88 }
89 // Convert the password from char[] to byte[]
90 byte[] passwdBytes = getPasswordBytes(this.passwd);
91
92 this.salt = keySpec.getSalt();
93 if (salt == null) {
94 throw new InvalidKeySpecException("Salt not found");
95 }
96 this.iterCount = keySpec.getIterationCount();
97 if (iterCount == 0) {
98 throw new InvalidKeySpecException("Iteration count not found");
99 } else if (iterCount < 0) {
100 throw new InvalidKeySpecException("Iteration count is negative");
101 }
102 int keyLength = keySpec.getKeyLength();
103 if (keyLength == 0) {
104 throw new InvalidKeySpecException("Key length not found");
105 } else if (keyLength == 0) {
106 throw new InvalidKeySpecException("Key length is negative");
107 }
108 try {
109 this.prf = Mac.getInstance(prfAlgo, "SunJCE");
110 } catch (NoSuchAlgorithmException nsae) {
111 // not gonna happen; re-throw just in case
112 InvalidKeySpecException ike = new InvalidKeySpecException();
113 ike.initCause(nsae);
114 throw ike;
115 } catch (NoSuchProviderException nspe) {
116 // Again, not gonna happen; re-throw just in case
117 InvalidKeySpecException ike = new InvalidKeySpecException();
118 ike.initCause(nspe);
119 throw ike;
120 }
121 this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
122 }
123
124 private static byte[] deriveKey(final Mac prf, final byte[] password,
125 byte[] salt, int iterCount, int keyLengthInBit) {
126 int keyLength = keyLengthInBit/8;
127 byte[] key = new byte[keyLength];
128 try {
129 int hlen = prf.getMacLength();
130 int intL = (keyLength + hlen - 1)/hlen; // ceiling
131 int intR = keyLength - (intL - 1)*hlen; // residue
132 byte[] ui = new byte[hlen];
133 byte[] ti = new byte[hlen];
134 // SecretKeySpec cannot be used, since password can be empty here.
135 SecretKey macKey = new SecretKey() {
136 @Override
137 public String getAlgorithm() {
138 return prf.getAlgorithm();
139 }
140 @Override
141 public String getFormat() {
142 return "RAW";
143 }
144 @Override
145 public byte[] getEncoded() {
146 return password;
147 }
148 @Override
149 public int hashCode() {
150 return Arrays.hashCode(password) * 41 +
151 prf.getAlgorithm().toLowerCase().hashCode();
152 }
153 @Override
154 public boolean equals(Object obj) {
155 if (this == obj) return true;
156 if (this.getClass() != obj.getClass()) return false;
157 SecretKey sk = (SecretKey)obj;
158 return prf.getAlgorithm().equalsIgnoreCase(
159 sk.getAlgorithm()) &&
160 Arrays.equals(password, sk.getEncoded());
161 }
162 };
163 prf.init(macKey);
164
165 byte[] ibytes = new byte[4];
166 for (int i = 1; i <= intL; i++) {
167 prf.update(salt);
168 ibytes[3] = (byte) i;
169 ibytes[2] = (byte) ((i >> 8) & 0xff);
170 ibytes[1] = (byte) ((i >> 16) & 0xff);
171 ibytes[0] = (byte) ((i >> 24) & 0xff);
172 prf.update(ibytes);
173 prf.doFinal(ui, 0);
174 System.arraycopy(ui, 0, ti, 0, ui.length);
175
176 for (int j = 2; j <= iterCount; j++) {
177 prf.update(ui);
178 prf.doFinal(ui, 0);
179 // XOR the intermediate Ui's together.
180 for (int k = 0; k < ui.length; k++) {
181 ti[k] ^= ui[k];
182 }
183 }
184 if (i == intL) {
185 System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
186 } else {
187 System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
188 }
189 }
190 } catch (GeneralSecurityException gse) {
191 throw new RuntimeException("Error deriving PBKDF2 keys");
192 }
193 return key;
194 }
195
196 public byte[] getEncoded() {
197 return (byte[]) key.clone();
198 }
199
200 public String getAlgorithm() {
201 return "PBKDF2With" + prf.getAlgorithm();
202 }
203
204 public int getIterationCount() {
205 return iterCount;
206 }
207
208 public char[] getPassword() {
209 return (char[]) passwd.clone();
210 }
211
212 public byte[] getSalt() {
213 return salt.clone();
214 }
215
216 public String getFormat() {
217 return "RAW";
218 }
219
220 /**
221 * Calculates a hash code value for the object.
222 * Objects that are equal will also have the same hashcode.
223 */
224 public int hashCode() {
225 int retval = 0;
226 for (int i = 1; i < this.key.length; i++) {
227 retval += this.key[i] * i;
228 }
229 return(retval ^= getAlgorithm().toLowerCase().hashCode());
230 }
231
232 public boolean equals(Object obj) {
233 if (obj == this)
234 return true;
235
236 if (!(obj instanceof SecretKey))
237 return false;
238
239 SecretKey that = (SecretKey) obj;
240
241 if (!(that.getAlgorithm().equalsIgnoreCase(getAlgorithm())))
242 return false;
243 if (!(that.getFormat().equalsIgnoreCase("RAW")))
244 return false;
245 byte[] thatEncoded = that.getEncoded();
246 boolean ret = Arrays.equals(key, that.getEncoded());
247 java.util.Arrays.fill(thatEncoded, (byte)0x00);
248 return ret;
249 }
250
251 /**
252 * Replace the PBE key to be serialized.
253 *
254 * @return the standard KeyRep object to be serialized
255 *
256 * @throws ObjectStreamException if a new object representing
257 * this PBE key could not be created
258 */
259 private Object writeReplace() throws ObjectStreamException {
260 return new KeyRep(KeyRep.Type.SECRET, getAlgorithm(),
261 getFormat(), getEncoded());
262 }
263
264 /**
265 * Ensures that the password bytes of this key are
266 * erased when there are no more references to it.
267 */
268 protected void finalize() throws Throwable {
269 try {
270 if (this.passwd != null) {
271 java.util.Arrays.fill(this.passwd, (char) '0');
272 this.passwd = null;
273 }
274 if (this.key != null) {
275 java.util.Arrays.fill(this.key, (byte)0x00);
276 this.key = null;
277 }
278 } finally {
279 super.finalize();
280 }
281 }
282}