src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java
changeset 51504 c9a3e3cac9c7
parent 47417 5984d1c9d03d
child 55493 159edfcbc2ce
equal deleted inserted replaced
51503:0265a70ea2a5 51504:c9a3e3cac9c7
    25 
    25 
    26 package com.sun.crypto.provider;
    26 package com.sun.crypto.provider;
    27 
    27 
    28 import java.security.*;
    28 import java.security.*;
    29 import java.security.spec.*;
    29 import java.security.spec.*;
       
    30 import java.util.Arrays;
    30 import javax.crypto.*;
    31 import javax.crypto.*;
    31 import javax.crypto.spec.*;
    32 import javax.crypto.spec.*;
    32 
    33 
    33 /**
    34 /**
    34  * This class represents password-based encryption as defined by the PKCS #5
    35  * This class represents password-based encryption as defined by the PKCS #5
   211         if (((opmode == Cipher.DECRYPT_MODE) ||
   212         if (((opmode == Cipher.DECRYPT_MODE) ||
   212              (opmode == Cipher.UNWRAP_MODE)) && (params == null)) {
   213              (opmode == Cipher.UNWRAP_MODE)) && (params == null)) {
   213             throw new InvalidAlgorithmParameterException("Parameters "
   214             throw new InvalidAlgorithmParameterException("Parameters "
   214                                                          + "missing");
   215                                                          + "missing");
   215         }
   216         }
   216         if ((key == null) ||
   217         if (key == null) {
   217             (key.getEncoded() == null) ||
   218             throw new InvalidKeyException("Null key");
   218             !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
   219         }
   219             throw new InvalidKeyException("Missing password");
   220 
   220         }
   221         byte[] derivedKey;
   221 
   222         byte[] passwdBytes = key.getEncoded();
   222         if (params == null) {
   223         try {
   223             // create random salt and use default iteration count
   224             if ((passwdBytes == null) ||
   224             salt = new byte[8];
   225                     !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
   225             random.nextBytes(salt);
   226                 throw new InvalidKeyException("Missing password");
   226         } else {
   227             }
   227             if (!(params instanceof PBEParameterSpec)) {
   228 
   228                 throw new InvalidAlgorithmParameterException
   229             if (params == null) {
   229                     ("Wrong parameter type: PBE expected");
   230                 // create random salt and use default iteration count
   230             }
   231                 salt = new byte[8];
   231             salt = ((PBEParameterSpec) params).getSalt();
   232                 random.nextBytes(salt);
   232             // salt must be 8 bytes long (by definition)
   233             } else {
   233             if (salt.length != 8) {
   234                 if (!(params instanceof PBEParameterSpec)) {
   234                 throw new InvalidAlgorithmParameterException
   235                     throw new InvalidAlgorithmParameterException
   235                     ("Salt must be 8 bytes long");
   236                             ("Wrong parameter type: PBE expected");
   236             }
   237                 }
   237             iCount = ((PBEParameterSpec) params).getIterationCount();
   238                 salt = ((PBEParameterSpec) params).getSalt();
   238             if (iCount <= 0) {
   239                 // salt must be 8 bytes long (by definition)
   239                 throw new InvalidAlgorithmParameterException
   240                 if (salt.length != 8) {
   240                     ("IterationCount must be a positive number");
   241                     throw new InvalidAlgorithmParameterException
   241             }
   242                             ("Salt must be 8 bytes long");
   242         }
   243                 }
   243 
   244                 iCount = ((PBEParameterSpec) params).getIterationCount();
   244         byte[] derivedKey = deriveCipherKey(key);
   245                 if (iCount <= 0) {
       
   246                     throw new InvalidAlgorithmParameterException
       
   247                             ("IterationCount must be a positive number");
       
   248                 }
       
   249             }
       
   250             derivedKey = deriveCipherKey(passwdBytes);
       
   251         } finally {
       
   252             if (passwdBytes != null) Arrays.fill(passwdBytes, (byte) 0x00);
       
   253         }
   245         // use all but the last 8 bytes as the key value
   254         // use all but the last 8 bytes as the key value
   246         SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, 0,
   255         SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, 0,
   247                                                     derivedKey.length-8, algo);
   256                                                     derivedKey.length-8, algo);
   248         // use the last 8 bytes as the IV
   257         // use the last 8 bytes as the IV
   249         IvParameterSpec ivSpec = new IvParameterSpec(derivedKey,
   258         IvParameterSpec ivSpec = new IvParameterSpec(derivedKey,
   251                                                      8);
   260                                                      8);
   252         // initialize the underlying cipher
   261         // initialize the underlying cipher
   253         cipher.init(opmode, cipherKey, ivSpec, random);
   262         cipher.init(opmode, cipherKey, ivSpec, random);
   254     }
   263     }
   255 
   264 
   256     private byte[] deriveCipherKey(Key key) {
   265     private byte[] deriveCipherKey(byte[] passwdBytes) {
   257 
   266 
   258         byte[] result = null;
   267         byte[] result = null;
   259         byte[] passwdBytes = key.getEncoded();
       
   260 
   268 
   261         if (algo.equals("DES")) {
   269         if (algo.equals("DES")) {
   262             // P || S (password concatenated with salt)
   270             // P || S (password concatenated with salt)
   263             byte[] concat = new byte[Math.addExact(passwdBytes.length, salt.length)];
   271             byte[] concat = new byte[Math.addExact(passwdBytes.length, salt.length)];
   264             System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length);
   272             System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length);
   265             java.util.Arrays.fill(passwdBytes, (byte)0x00);
       
   266             System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length);
   273             System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length);
   267 
   274 
   268             // digest P || S with c iterations
   275             // digest P || S with c iterations
   269             byte[] toBeHashed = concat;
   276             byte[] toBeHashed = concat;
   270             for (int i = 0; i < iCount; i++) {
   277             for (int i = 0; i < iCount; i++) {
   271                 md.update(toBeHashed);
   278                 md.update(toBeHashed);
   272                 toBeHashed = md.digest(); // this resets the digest
   279                 toBeHashed = md.digest(); // this resets the digest
   273             }
   280             }
   274             java.util.Arrays.fill(concat, (byte)0x00);
   281             Arrays.fill(concat, (byte)0x00);
   275             result = toBeHashed;
   282             result = toBeHashed;
   276         } else if (algo.equals("DESede")) {
   283         } else if (algo.equals("DESede")) {
   277             // if the 2 salt halves are the same, invert one of them
   284             // if the 2 salt halves are the same, invert one of them
   278             int i;
   285             int i;
   279             for (i=0; i<4; i++) {
   286             for (i=0; i<4; i++) {
   292             // half, go through the loop as many times as specified by the
   299             // half, go through the loop as many times as specified by the
   293             // iteration count parameter (inner for loop).
   300             // iteration count parameter (inner for loop).
   294             // Concatenate the output from each digest round with the
   301             // Concatenate the output from each digest round with the
   295             // password, and use the result as the input to the next digest
   302             // password, and use the result as the input to the next digest
   296             // operation.
   303             // operation.
   297             byte[] kBytes = null;
       
   298             IvParameterSpec iv = null;
       
   299             byte[] toBeHashed = null;
   304             byte[] toBeHashed = null;
   300             result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN +
   305             result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN +
   301                               DESConstants.DES_BLOCK_SIZE];
   306                               DESConstants.DES_BLOCK_SIZE];
   302             for (i = 0; i < 2; i++) {
   307             for (i = 0; i < 2; i++) {
   303                 toBeHashed = new byte[salt.length/2];
   308                 toBeHashed = new byte[salt.length/2];
   304                 System.arraycopy(salt, i*(salt.length/2), toBeHashed, 0,
   309                 System.arraycopy(salt, i*(salt.length/2), toBeHashed, 0,
   305                                  toBeHashed.length);
   310                                  toBeHashed.length);
   306                 for (int j=0; j < iCount; j++) {
   311                 for (int j=0; j < iCount; j++) {
   307                     md.update(toBeHashed);
   312                     md.update(toBeHashed);
   308                     md.update(passwdBytes);
   313                     md.update(passwdBytes);
   309                     toBeHashed = md.digest(); // this resets the digest
   314                     toBeHashed = md.digest();
   310                 }
   315                 }
   311                 System.arraycopy(toBeHashed, 0, result, i*16,
   316                 System.arraycopy(toBeHashed, 0, result, i*16,
   312                                  toBeHashed.length);
   317                                  toBeHashed.length);
   313             }
   318             }
   314         }
   319         }
       
   320         // clear data used in message
       
   321         md.reset();
   315         return result;
   322         return result;
   316     }
   323     }
   317 
   324 
   318     void init(int opmode, Key key, AlgorithmParameters params,
   325     void init(int opmode, Key key, AlgorithmParameters params,
   319               SecureRandom random)
   326               SecureRandom random)
   476      * being passed to a software only cipher).
   483      * being passed to a software only cipher).
   477      */
   484      */
   478     byte[] wrap(Key key)
   485     byte[] wrap(Key key)
   479         throws IllegalBlockSizeException, InvalidKeyException {
   486         throws IllegalBlockSizeException, InvalidKeyException {
   480         byte[] result = null;
   487         byte[] result = null;
   481 
   488         byte[] encodedKey = null;
   482         try {
   489         try {
   483             byte[] encodedKey = key.getEncoded();
   490             encodedKey = key.getEncoded();
   484             if ((encodedKey == null) || (encodedKey.length == 0)) {
   491             if ((encodedKey == null) || (encodedKey.length == 0)) {
   485                 throw new InvalidKeyException("Cannot get an encoding of " +
   492                 throw new InvalidKeyException("Cannot get an encoding of " +
   486                                               "the key to be wrapped");
   493                                               "the key to be wrapped");
   487             }
   494             }
   488 
   495 
   489             result = doFinal(encodedKey, 0, encodedKey.length);
   496             result = doFinal(encodedKey, 0, encodedKey.length);
   490         } catch (BadPaddingException e) {
   497         } catch (BadPaddingException e) {
   491             // Should never happen
   498             // Should never happen
       
   499         } finally {
       
   500             if (encodedKey != null) Arrays.fill(encodedKey, (byte)0x00);
   492         }
   501         }
   493 
   502 
   494         return result;
   503         return result;
   495     }
   504     }
   496 
   505