11/*
2- * Copyright (c) 2012, 2022 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2012, 2023 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
3131import javax .crypto .*;
3232import javax .crypto .spec .*;
3333
34+ import jdk .internal .access .SharedSecrets ;
35+ import sun .security .util .PBEUtil ;
36+
3437/**
3538 * This class represents password-based encryption as defined by the PKCS #5
3639 * standard.
4346 * @see javax.crypto.Cipher
4447 */
4548abstract class PBES2Core extends CipherSpi {
46-
47- private static final int DEFAULT_SALT_LENGTH = 20 ;
48- private static final int DEFAULT_COUNT = 4096 ;
49-
5049 // the encapsulated cipher
5150 private final CipherCore cipher ;
5251 private final int keyLength ; // in bits
5352 private final int blkSize ; // in bits
5453 private final PBKDF2Core kdf ;
5554 private final String pbeAlgo ;
5655 private final String cipherAlgo ;
57- private int iCount = DEFAULT_COUNT ;
58- private byte [] salt = null ;
59- private IvParameterSpec ivSpec = null ;
56+ private final PBEUtil .PBES2Params pbes2Params = new PBEUtil .PBES2Params ();
6057
6158 /**
6259 * Creates an instance of PBE Scheme 2 according to the selected
@@ -135,32 +132,8 @@ protected byte[] engineGetIV() {
135132 }
136133
137134 protected AlgorithmParameters engineGetParameters () {
138- AlgorithmParameters params = null ;
139- if (salt == null ) {
140- // generate random salt and use default iteration count
141- salt = new byte [DEFAULT_SALT_LENGTH ];
142- SunJCE .getRandom ().nextBytes (salt );
143- iCount = DEFAULT_COUNT ;
144- }
145- if (ivSpec == null ) {
146- // generate random IV
147- byte [] ivBytes = new byte [blkSize ];
148- SunJCE .getRandom ().nextBytes (ivBytes );
149- ivSpec = new IvParameterSpec (ivBytes );
150- }
151- PBEParameterSpec pbeSpec = new PBEParameterSpec (salt , iCount , ivSpec );
152- try {
153- params = AlgorithmParameters .getInstance (pbeAlgo ,
154- SunJCE .getInstance ());
155- params .init (pbeSpec );
156- } catch (NoSuchAlgorithmException nsae ) {
157- // should never happen
158- throw new RuntimeException ("SunJCE called, but not configured" );
159- } catch (InvalidParameterSpecException ipse ) {
160- // should never happen
161- throw new RuntimeException ("PBEParameterSpec not supported" );
162- }
163- return params ;
135+ return pbes2Params .getAlgorithmParameters (
136+ blkSize , pbeAlgo , SunJCE .getInstance (), SunJCE .getRandom ());
164137 }
165138
166139 protected void engineInit (int opmode , Key key , SecureRandom random )
@@ -172,132 +145,46 @@ protected void engineInit(int opmode, Key key, SecureRandom random)
172145 }
173146 }
174147
175- private static byte [] check (byte [] salt )
176- throws InvalidAlgorithmParameterException {
177- if (salt != null && salt .length < 8 ) {
178- throw new InvalidAlgorithmParameterException (
179- "Salt must be at least 8 bytes long" );
180- }
181- return salt ;
182- }
183-
184- private static int check (int iCount )
185- throws InvalidAlgorithmParameterException {
186- if (iCount < 0 ) {
187- throw new InvalidAlgorithmParameterException (
188- "Iteration count must be a positive number" );
189- }
190- return iCount == 0 ? DEFAULT_COUNT : iCount ;
191- }
192-
193148 protected void engineInit (int opmode , Key key ,
194149 AlgorithmParameterSpec params ,
195150 SecureRandom random )
196151 throws InvalidKeyException , InvalidAlgorithmParameterException {
197152
198- if (key == null ) {
199- throw new InvalidKeyException ("Null key" );
200- }
201-
202- byte [] passwdBytes = key .getEncoded ();
203- char [] passwdChars = null ;
204- salt = null ;
205- iCount = 0 ;
206- ivSpec = null ;
207-
208- PBEKeySpec pbeSpec ;
209- try {
210- if ((passwdBytes == null ) ||
211- !(key .getAlgorithm ().regionMatches (true , 0 , "PBE" , 0 , 3 ))) {
212- throw new InvalidKeyException ("Missing password" );
213- }
214-
215- boolean doEncrypt = ((opmode == Cipher .ENCRYPT_MODE ) ||
216- (opmode == Cipher .WRAP_MODE ));
217-
218- // Extract from the supplied PBE params, if present
219- if (params instanceof PBEParameterSpec pbeParams ) {
220- // salt should be non-null per PBEParameterSpec
221- salt = check (pbeParams .getSalt ());
222- iCount = check (pbeParams .getIterationCount ());
223- AlgorithmParameterSpec ivParams = pbeParams .getParameterSpec ();
224- if (ivParams instanceof IvParameterSpec iv ) {
225- ivSpec = iv ;
226- } else if (ivParams == null && doEncrypt ) {
227- // generate random IV
228- byte [] ivBytes = new byte [blkSize ];
229- random .nextBytes (ivBytes );
230- ivSpec = new IvParameterSpec (ivBytes );
231- } else {
232- throw new InvalidAlgorithmParameterException (
233- "Wrong parameter type: IV expected" );
234- }
235- } else if (params == null && doEncrypt ) {
236- // Try extracting from the key if present. If unspecified,
237- // PBEKey returns null and 0 respectively.
238- if (key instanceof javax .crypto .interfaces .PBEKey pbeKey ) {
239- salt = check (pbeKey .getSalt ());
240- iCount = check (pbeKey .getIterationCount ());
241- }
242- if (salt == null ) {
243- // generate random salt
244- salt = new byte [DEFAULT_SALT_LENGTH ];
245- random .nextBytes (salt );
246- }
247- if (iCount == 0 ) {
248- // use default iteration count
249- iCount = DEFAULT_COUNT ;
250- }
251- // generate random IV
252- byte [] ivBytes = new byte [blkSize ];
253- random .nextBytes (ivBytes );
254- ivSpec = new IvParameterSpec (ivBytes );
255- } else {
256- throw new InvalidAlgorithmParameterException
257- ("Wrong parameter type: PBE expected" );
258- }
259- passwdChars = new char [passwdBytes .length ];
260- for (int i = 0 ; i < passwdChars .length ; i ++)
261- passwdChars [i ] = (char ) (passwdBytes [i ] & 0x7f );
262-
263- pbeSpec = new PBEKeySpec (passwdChars , salt , iCount , keyLength );
264- } finally {
265- // password char[] was cloned in PBEKeySpec constructor,
266- // so we can zero it out here
267- if (passwdChars != null ) Arrays .fill (passwdChars , '\0' );
268- if (passwdBytes != null ) Arrays .fill (passwdBytes , (byte )0x00 );
269- }
270-
271- PBKDF2KeyImpl s ;
272-
153+ PBEKeySpec pbeSpec = pbes2Params .getPBEKeySpec (blkSize , keyLength ,
154+ opmode , key , params , random );
155+ PBKDF2KeyImpl s = null ;
156+ byte [] derivedKey ;
273157 try {
274158 s = (PBKDF2KeyImpl )kdf .engineGenerateSecret (pbeSpec );
159+ derivedKey = s .getEncoded ();
275160 } catch (InvalidKeySpecException ikse ) {
276161 throw new InvalidKeyException ("Cannot construct PBE key" , ikse );
277162 } finally {
163+ if (s != null ) {
164+ s .clear ();
165+ }
278166 pbeSpec .clearPassword ();
279167 }
280- byte [] derivedKey = s .getEncoded ();
281- s .clearPassword ();
282- SecretKeySpec cipherKey = new SecretKeySpec (derivedKey , cipherAlgo );
283168
284- // initialize the underlying cipher
285- cipher .init (opmode , cipherKey , ivSpec , random );
169+ SecretKeySpec cipherKey = null ;
170+ try {
171+ cipherKey = new SecretKeySpec (derivedKey , cipherAlgo );
172+ // initialize the underlying cipher
173+ cipher .init (opmode , cipherKey , pbes2Params .getIvSpec (), random );
174+ } finally {
175+ if (cipherKey != null ) {
176+ SharedSecrets .getJavaxCryptoSpecAccess ()
177+ .clearSecretKeySpec (cipherKey );
178+ }
179+ Arrays .fill (derivedKey , (byte ) 0 );
180+ }
286181 }
287182
288183 protected void engineInit (int opmode , Key key , AlgorithmParameters params ,
289184 SecureRandom random )
290185 throws InvalidKeyException , InvalidAlgorithmParameterException {
291- AlgorithmParameterSpec pbeSpec = null ;
292- if (params != null ) {
293- try {
294- pbeSpec = params .getParameterSpec (PBEParameterSpec .class );
295- } catch (InvalidParameterSpecException ipse ) {
296- throw new InvalidAlgorithmParameterException (
297- "Wrong parameter type: PBE expected" );
298- }
299- }
300- engineInit (opmode , key , pbeSpec , random );
186+ engineInit (opmode , key , PBEUtil .PBES2Params .getParameterSpec (params ),
187+ random );
301188 }
302189
303190 protected byte [] engineUpdate (byte [] input , int inputOffset , int inputLen ) {
0 commit comments