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+
26+package com.sun.crypto.provider;
27+
28+import java.io.ObjectStreamException;
29+import java.nio.ByteBuffer;
30+import java.nio.CharBuffer;
31+import java.nio.charset.Charset;
32+import java.util.Arrays;
33+import java.security.KeyRep;
34+import java.security.GeneralSecurityException;
35+import java.security.NoSuchAlgorithmException;
36+import java.security.NoSuchProviderException;
37+import java.security.spec.InvalidKeySpecException;
38+import javax.crypto.Mac;
39+import javax.crypto.SecretKey;
40+import 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+ */
52+final 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+}