src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java
changeset 51293 53c3b460503c
parent 49783 977c6dd636bd
child 51504 c9a3e3cac9c7
equal deleted inserted replaced
51292:0538a5cdb474 51293:53c3b460503c
    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;
   352             throw new UnrecoverableKeyException(ioe.getMessage());
   372             throw new UnrecoverableKeyException(ioe.getMessage());
   353         } catch (ClassNotFoundException cnfe) {
   373         } catch (ClassNotFoundException cnfe) {
   354             throw new UnrecoverableKeyException(cnfe.getMessage());
   374             throw new UnrecoverableKeyException(cnfe.getMessage());
   355         } catch (GeneralSecurityException gse) {
   375         } catch (GeneralSecurityException gse) {
   356             throw new UnrecoverableKeyException(gse.getMessage());
   376             throw new UnrecoverableKeyException(gse.getMessage());
       
   377         } finally {
       
   378             if (sKey != null) {
       
   379                 try {
       
   380                     sKey.destroy();
       
   381                 } catch (DestroyFailedException e) {
       
   382                     //shouldn't happen
       
   383                 }
       
   384             }
   357         }
   385         }
   358     }
   386     }
   359 }
   387 }
   360 
   388 
   361 
   389