35 import java.security.NoSuchAlgorithmException; |
35 import java.security.NoSuchAlgorithmException; |
36 import java.security.UnrecoverableKeyException; |
36 import java.security.UnrecoverableKeyException; |
37 import java.security.AlgorithmParameters; |
37 import java.security.AlgorithmParameters; |
38 import java.security.spec.InvalidParameterSpecException; |
38 import java.security.spec.InvalidParameterSpecException; |
39 import java.security.spec.PKCS8EncodedKeySpec; |
39 import java.security.spec.PKCS8EncodedKeySpec; |
|
40 import java.util.Arrays; |
40 |
41 |
41 import javax.crypto.Cipher; |
42 import javax.crypto.Cipher; |
42 import javax.crypto.CipherSpi; |
43 import javax.crypto.CipherSpi; |
43 import javax.crypto.SecretKey; |
44 import javax.crypto.SecretKey; |
44 import javax.crypto.SealedObject; |
45 import javax.crypto.SealedObject; |
45 import javax.crypto.spec.*; |
46 import javax.crypto.spec.*; |
|
47 import javax.security.auth.DestroyFailedException; |
|
48 |
46 import sun.security.x509.AlgorithmId; |
49 import sun.security.x509.AlgorithmId; |
47 import sun.security.util.ObjectIdentifier; |
50 import sun.security.util.ObjectIdentifier; |
48 |
51 |
49 /** |
52 /** |
50 * This class implements a protection mechanism for private keys. In JCE, we |
53 * This class implements a protection mechanism for private keys. In JCE, we |
101 // create PBE parameters from salt and iteration count |
104 // create PBE parameters from salt and iteration count |
102 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT); |
105 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT); |
103 |
106 |
104 // create PBE key from password |
107 // create PBE key from password |
105 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
108 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
106 SecretKey sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); |
109 SecretKey sKey = null; |
107 pbeKeySpec.clearPassword(); |
|
108 |
|
109 // encrypt private key |
|
110 PBEWithMD5AndTripleDESCipher cipher; |
110 PBEWithMD5AndTripleDESCipher cipher; |
111 cipher = new PBEWithMD5AndTripleDESCipher(); |
111 try { |
112 cipher.engineInit(Cipher.ENCRYPT_MODE, sKey, pbeSpec, null); |
112 sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); |
|
113 // encrypt private key |
|
114 cipher = new PBEWithMD5AndTripleDESCipher(); |
|
115 cipher.engineInit(Cipher.ENCRYPT_MODE, sKey, pbeSpec, null); |
|
116 } finally { |
|
117 pbeKeySpec.clearPassword(); |
|
118 if (sKey != null) sKey.destroy(); |
|
119 } |
113 byte[] plain = key.getEncoded(); |
120 byte[] plain = key.getEncoded(); |
114 byte[] encrKey = cipher.engineDoFinal(plain, 0, plain.length); |
121 byte[] encrKey = cipher.engineDoFinal(plain, 0, plain.length); |
|
122 Arrays.fill(plain, (byte) 0x00); |
115 |
123 |
116 // wrap encrypted private key in EncryptedPrivateKeyInfo |
124 // wrap encrypted private key in EncryptedPrivateKeyInfo |
117 // (as defined in PKCS#8) |
125 // (as defined in PKCS#8) |
118 AlgorithmParameters pbeParams = |
126 AlgorithmParameters pbeParams = |
119 AlgorithmParameters.getInstance("PBE", SunJCE.getInstance()); |
127 AlgorithmParameters.getInstance("PBE", SunJCE.getInstance()); |
129 * using the password provided at construction time. |
137 * using the password provided at construction time. |
130 */ |
138 */ |
131 Key recover(EncryptedPrivateKeyInfo encrInfo) |
139 Key recover(EncryptedPrivateKeyInfo encrInfo) |
132 throws UnrecoverableKeyException, NoSuchAlgorithmException |
140 throws UnrecoverableKeyException, NoSuchAlgorithmException |
133 { |
141 { |
134 byte[] plain; |
142 byte[] plain = null; |
135 |
143 SecretKey sKey = null; |
136 try { |
144 try { |
137 String encrAlg = encrInfo.getAlgorithm().getOID().toString(); |
145 String encrAlg = encrInfo.getAlgorithm().getOID().toString(); |
138 if (!encrAlg.equals(PBE_WITH_MD5_AND_DES3_CBC_OID) |
146 if (!encrAlg.equals(PBE_WITH_MD5_AND_DES3_CBC_OID) |
139 && !encrAlg.equals(KEY_PROTECTOR_OID)) { |
147 && !encrAlg.equals(KEY_PROTECTOR_OID)) { |
140 throw new UnrecoverableKeyException("Unsupported encryption " |
148 throw new UnrecoverableKeyException("Unsupported encryption " |
158 throw new IOException("PBE iteration count too large"); |
166 throw new IOException("PBE iteration count too large"); |
159 } |
167 } |
160 |
168 |
161 // create PBE key from password |
169 // create PBE key from password |
162 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
170 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
163 SecretKey sKey = |
171 sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); |
164 new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); |
|
165 pbeKeySpec.clearPassword(); |
172 pbeKeySpec.clearPassword(); |
166 |
173 |
167 // decrypt private key |
174 // decrypt private key |
168 PBEWithMD5AndTripleDESCipher cipher; |
175 PBEWithMD5AndTripleDESCipher cipher; |
169 cipher = new PBEWithMD5AndTripleDESCipher(); |
176 cipher = new PBEWithMD5AndTripleDESCipher(); |
176 // using the appropriate key factory |
183 // using the appropriate key factory |
177 String oidName = new AlgorithmId |
184 String oidName = new AlgorithmId |
178 (new PrivateKeyInfo(plain).getAlgorithm().getOID()).getName(); |
185 (new PrivateKeyInfo(plain).getAlgorithm().getOID()).getName(); |
179 KeyFactory kFac = KeyFactory.getInstance(oidName); |
186 KeyFactory kFac = KeyFactory.getInstance(oidName); |
180 return kFac.generatePrivate(new PKCS8EncodedKeySpec(plain)); |
187 return kFac.generatePrivate(new PKCS8EncodedKeySpec(plain)); |
181 |
|
182 } catch (NoSuchAlgorithmException ex) { |
188 } catch (NoSuchAlgorithmException ex) { |
183 // Note: this catch needed to be here because of the |
189 // Note: this catch needed to be here because of the |
184 // later catch of GeneralSecurityException |
190 // later catch of GeneralSecurityException |
185 throw ex; |
191 throw ex; |
186 } catch (IOException ioe) { |
192 } catch (IOException ioe) { |
187 throw new UnrecoverableKeyException(ioe.getMessage()); |
193 throw new UnrecoverableKeyException(ioe.getMessage()); |
188 } catch (GeneralSecurityException gse) { |
194 } catch (GeneralSecurityException gse) { |
189 throw new UnrecoverableKeyException(gse.getMessage()); |
195 throw new UnrecoverableKeyException(gse.getMessage()); |
|
196 } finally { |
|
197 if (plain != null) Arrays.fill(plain, (byte) 0x00); |
|
198 if (sKey != null) { |
|
199 try { |
|
200 sKey.destroy(); |
|
201 } catch (DestroyFailedException e) { |
|
202 //shouldn't happen |
|
203 } |
|
204 } |
190 } |
205 } |
191 } |
206 } |
192 |
207 |
193 /* |
208 /* |
194 * Recovers the cleartext version of the given key (in protected format), |
209 * Recovers the cleartext version of the given key (in protected format), |
260 // the password, digesting the concatenation, and comparing the |
275 // the password, digesting the concatenation, and comparing the |
261 // result of the digest operation with the digest provided at the end |
276 // result of the digest operation with the digest provided at the end |
262 // of <code>protectedKey</code>. If the two digest values are |
277 // of <code>protectedKey</code>. If the two digest values are |
263 // different, throw an exception. |
278 // different, throw an exception. |
264 md.update(passwdBytes); |
279 md.update(passwdBytes); |
265 java.util.Arrays.fill(passwdBytes, (byte)0x00); |
280 Arrays.fill(passwdBytes, (byte)0x00); |
266 passwdBytes = null; |
281 passwdBytes = null; |
267 md.update(plainKey); |
282 md.update(plainKey); |
268 digest = md.digest(); |
283 digest = md.digest(); |
269 md.reset(); |
284 md.reset(); |
270 for (i = 0; i < digest.length; i++) { |
285 for (i = 0; i < digest.length; i++) { |
289 // create PBE parameters from salt and iteration count |
304 // create PBE parameters from salt and iteration count |
290 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT); |
305 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, ITERATION_COUNT); |
291 |
306 |
292 // create PBE key from password |
307 // create PBE key from password |
293 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
308 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
294 SecretKey sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); |
309 SecretKey sKey = null; |
|
310 Cipher cipher; |
|
311 try { |
|
312 sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); |
295 pbeKeySpec.clearPassword(); |
313 pbeKeySpec.clearPassword(); |
296 |
314 |
297 // seal key |
315 // seal key |
298 Cipher cipher; |
|
299 |
|
300 PBEWithMD5AndTripleDESCipher cipherSpi; |
316 PBEWithMD5AndTripleDESCipher cipherSpi; |
301 cipherSpi = new PBEWithMD5AndTripleDESCipher(); |
317 cipherSpi = new PBEWithMD5AndTripleDESCipher(); |
302 cipher = new CipherForKeyProtector(cipherSpi, SunJCE.getInstance(), |
318 cipher = new CipherForKeyProtector(cipherSpi, SunJCE.getInstance(), |
303 "PBEWithMD5AndTripleDES"); |
319 "PBEWithMD5AndTripleDES"); |
304 cipher.init(Cipher.ENCRYPT_MODE, sKey, pbeSpec); |
320 cipher.init(Cipher.ENCRYPT_MODE, sKey, pbeSpec); |
|
321 } finally { |
|
322 if (sKey != null) sKey.destroy(); |
|
323 } |
305 return new SealedObjectForKeyProtector(key, cipher); |
324 return new SealedObjectForKeyProtector(key, cipher); |
306 } |
325 } |
307 |
326 |
308 /** |
327 /** |
309 * Unseals the sealed key. |
328 * Unseals the sealed key. |
310 */ |
329 */ |
311 Key unseal(SealedObject so) |
330 Key unseal(SealedObject so) |
312 throws NoSuchAlgorithmException, UnrecoverableKeyException |
331 throws NoSuchAlgorithmException, UnrecoverableKeyException { |
313 { |
332 SecretKey sKey = null; |
314 try { |
333 try { |
315 // create PBE key from password |
334 // create PBE key from password |
316 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
335 PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); |
317 SecretKey skey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); |
336 sKey = new PBEKey(pbeKeySpec, |
|
337 "PBEWithMD5AndTripleDES", false); |
318 pbeKeySpec.clearPassword(); |
338 pbeKeySpec.clearPassword(); |
319 |
339 |
320 SealedObjectForKeyProtector soForKeyProtector = null; |
340 SealedObjectForKeyProtector soForKeyProtector = null; |
321 if (!(so instanceof SealedObjectForKeyProtector)) { |
341 if (!(so instanceof SealedObjectForKeyProtector)) { |
322 soForKeyProtector = new SealedObjectForKeyProtector(so); |
342 soForKeyProtector = new SealedObjectForKeyProtector(so); |
340 PBEWithMD5AndTripleDESCipher cipherSpi; |
360 PBEWithMD5AndTripleDESCipher cipherSpi; |
341 cipherSpi = new PBEWithMD5AndTripleDESCipher(); |
361 cipherSpi = new PBEWithMD5AndTripleDESCipher(); |
342 Cipher cipher = new CipherForKeyProtector(cipherSpi, |
362 Cipher cipher = new CipherForKeyProtector(cipherSpi, |
343 SunJCE.getInstance(), |
363 SunJCE.getInstance(), |
344 "PBEWithMD5AndTripleDES"); |
364 "PBEWithMD5AndTripleDES"); |
345 cipher.init(Cipher.DECRYPT_MODE, skey, params); |
365 cipher.init(Cipher.DECRYPT_MODE, sKey, params); |
346 return soForKeyProtector.getKey(cipher); |
366 return soForKeyProtector.getKey(cipher); |
347 } catch (NoSuchAlgorithmException ex) { |
367 } catch (NoSuchAlgorithmException ex) { |
348 // Note: this catch needed to be here because of the |
368 // Note: this catch needed to be here because of the |
349 // later catch of GeneralSecurityException |
369 // later catch of GeneralSecurityException |
350 throw ex; |
370 throw ex; |