blob: 150477c5ea12604c2e07eae4e5a695772aae5dc7 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.crypto.provider;
27
28import java.util.Arrays;
29import java.nio.ByteBuffer;
30
31import javax.crypto.MacSpi;
32import javax.crypto.SecretKey;
33import javax.crypto.spec.SecretKeySpec;
34import javax.crypto.spec.PBEParameterSpec;
35import java.security.*;
36import java.security.spec.*;
37
38/**
39 * This is an implementation of the HMAC-PBESHA1 algorithm as defined
40 * in PKCS#12 v1.0 standard.
41 *
42 * @author Valerie Peng
43 */
44public final class HmacPKCS12PBESHA1 extends MacSpi implements Cloneable {
45
46 private HmacCore hmac = null;
47 private static final int SHA1_BLOCK_LENGTH = 64;
48
49 /**
50 * Standard constructor, creates a new HmacSHA1 instance.
51 * Verify the SunJCE provider in the constructor.
52 *
53 * @exception SecurityException if fails to verify
54 * its own integrity
55 */
56 public HmacPKCS12PBESHA1() throws NoSuchAlgorithmException {
57 SunJCE.ensureIntegrity(this.getClass());
58 this.hmac = new HmacCore(MessageDigest.getInstance("SHA1"),
59 SHA1_BLOCK_LENGTH);
60 }
61
62 /**
63 * Returns the length of the HMAC in bytes.
64 *
65 * @return the HMAC length in bytes.
66 */
67 protected int engineGetMacLength() {
68 return hmac.getDigestLength();
69 }
70
71 /**
72 * Initializes the HMAC with the given secret key and algorithm parameters.
73 *
74 * @param key the secret key.
75 * @param params the algorithm parameters.
76 *
77 * @exception InvalidKeyException if the given key is inappropriate for
78 * initializing this MAC.
79 u* @exception InvalidAlgorithmParameterException if the given algorithm
80 * parameters are inappropriate for this MAC.
81 */
82 protected void engineInit(Key key, AlgorithmParameterSpec params)
83 throws InvalidKeyException, InvalidAlgorithmParameterException {
84 char[] passwdChars;
85 byte[] salt = null;
86 int iCount = 0;
87 if (key instanceof javax.crypto.interfaces.PBEKey) {
88 javax.crypto.interfaces.PBEKey pbeKey =
89 (javax.crypto.interfaces.PBEKey) key;
90 passwdChars = pbeKey.getPassword();
91 salt = pbeKey.getSalt(); // maybe null if unspecified
92 iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
93 } else if (key instanceof SecretKey) {
94 byte[] passwdBytes = key.getEncoded();
95 if ((passwdBytes == null) ||
96 !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
97 throw new InvalidKeyException("Missing password");
98 }
99 passwdChars = new char[passwdBytes.length];
100 for (int i=0; i<passwdChars.length; i++) {
101 passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
102 }
103 } else {
104 throw new InvalidKeyException("SecretKey of PBE type required");
105 }
106 if (params == null) {
107 // generate default for salt and iteration count if necessary
108 if (salt == null) {
109 salt = new byte[20];
110 SunJCE.RANDOM.nextBytes(salt);
111 }
112 if (iCount == 0) iCount = 100;
113 } else if (!(params instanceof PBEParameterSpec)) {
114 throw new InvalidAlgorithmParameterException
115 ("PBEParameterSpec type required");
116 } else {
117 PBEParameterSpec pbeParams = (PBEParameterSpec) params;
118 // make sure the parameter values are consistent
119 if (salt != null) {
120 if (!Arrays.equals(salt, pbeParams.getSalt())) {
121 throw new InvalidAlgorithmParameterException
122 ("Inconsistent value of salt between key and params");
123 }
124 } else {
125 salt = pbeParams.getSalt();
126 }
127 if (iCount != 0) {
128 if (iCount != pbeParams.getIterationCount()) {
129 throw new InvalidAlgorithmParameterException
130 ("Different iteration count between key and params");
131 }
132 } else {
133 iCount = pbeParams.getIterationCount();
134 }
135 }
136 // For security purpose, we need to enforce a minimum length
137 // for salt; just require the minimum salt length to be 8-byte
138 // which is what PKCS#5 recommends and openssl does.
139 if (salt.length < 8) {
140 throw new InvalidAlgorithmParameterException
141 ("Salt must be at least 8 bytes long");
142 }
143 if (iCount <= 0) {
144 throw new InvalidAlgorithmParameterException
145 ("IterationCount must be a positive number");
146 }
147 byte[] derivedKey = PKCS12PBECipherCore.derive(passwdChars, salt,
148 iCount, hmac.getDigestLength(), PKCS12PBECipherCore.MAC_KEY);
149 SecretKey cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
150 hmac.init(cipherKey, null);
151 }
152
153 /**
154 * Processes the given byte.
155 *
156 * @param input the input byte to be processed.
157 */
158 protected void engineUpdate(byte input) {
159 hmac.update(input);
160 }
161
162 /**
163 * Processes the first <code>len</code> bytes in <code>input</code>,
164 * starting at <code>offset</code>.
165 *
166 * @param input the input buffer.
167 * @param offset the offset in <code>input</code> where the input starts.
168 * @param len the number of bytes to process.
169 */
170 protected void engineUpdate(byte input[], int offset, int len) {
171 hmac.update(input, offset, len);
172 }
173
174 protected void engineUpdate(ByteBuffer input) {
175 hmac.update(input);
176 }
177
178 /**
179 * Completes the HMAC computation and resets the HMAC for further use,
180 * maintaining the secret key that the HMAC was initialized with.
181 *
182 * @return the HMAC result.
183 */
184 protected byte[] engineDoFinal() {
185 return hmac.doFinal();
186 }
187
188 /**
189 * Resets the HMAC for further use, maintaining the secret key that the
190 * HMAC was initialized with.
191 */
192 protected void engineReset() {
193 hmac.reset();
194 }
195
196 /*
197 * Clones this object.
198 */
199 public Object clone() {
200 HmacPKCS12PBESHA1 that = null;
201 try {
202 that = (HmacPKCS12PBESHA1)super.clone();
203 that.hmac = (HmacCore)this.hmac.clone();
204 } catch (CloneNotSupportedException e) {
205 }
206 return that;
207 }
208}