5757
5858public class EncryptedPrivateKeyInfo {
5959
60- // the "encryptionAlgorithm" field
60+ // The "encryptionAlgorithm" is stored in either the algid or
61+ // the params field. Precisely, if this object is created by
62+ // {@link #EncryptedPrivateKeyInfo(AlgorithmParameters, byte[])}
63+ // with an uninitialized AlgorithmParameters, the AlgorithmParameters
64+ // object is stored in the params field and algid is set to null.
65+ // In all other cases, algid is non null and params is null.
6166 private final AlgorithmId algid ;
62-
63- // the algorithm name of the encrypted private key
64- private String keyAlg ;
67+ private final AlgorithmParameters params ;
6568
6669 // the "encryptedData" field
6770 private final byte [] encryptedData ;
6871
6972 // the ASN.1 encoded contents of this class
70- private byte [] encoded ;
73+ private final byte [] encoded ;
7174
7275 /**
7376 * Constructs (i.e., parses) an {@code EncryptedPrivateKeyInfo} from
@@ -100,6 +103,7 @@ public EncryptedPrivateKeyInfo(byte[] encoded) throws IOException {
100103 }
101104
102105 this .algid = AlgorithmId .parse (seq [0 ]);
106+ this .params = null ;
103107 if (seq [0 ].data .available () != 0 ) {
104108 throw new IOException ("encryptionAlgorithm field overrun" );
105109 }
@@ -141,6 +145,7 @@ public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
141145 throw new NullPointerException ("the algName parameter " +
142146 "must be non-null" );
143147 this .algid = AlgorithmId .get (algName );
148+ this .params = null ;
144149
145150 if (encryptedData == null ) {
146151 throw new NullPointerException ("the encryptedData " +
@@ -181,7 +186,22 @@ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
181186 if (algParams == null ) {
182187 throw new NullPointerException ("algParams must be non-null" );
183188 }
184- this .algid = AlgorithmId .get (algParams );
189+ AlgorithmId tmp ;
190+ try {
191+ tmp = AlgorithmId .get (algParams );
192+ } catch (IllegalStateException e ) {
193+ // This exception is thrown when algParams.getEncoded() fails.
194+ // While the spec of this constructor requires that
195+ // "getEncoded should return...", in reality people might
196+ // create with an uninitialized algParams first and only
197+ // initialize it before calling getEncoded(). Thus we support
198+ // this case as well.
199+ tmp = null ;
200+ }
201+
202+ // one and only one is non null
203+ this .algid = tmp ;
204+ this .params = this .algid != null ? null : algParams ;
185205
186206 if (encryptedData == null ) {
187207 throw new NullPointerException ("encryptedData must be non-null" );
@@ -197,7 +217,6 @@ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
197217 this .encoded = null ;
198218 }
199219
200-
201220 /**
202221 * Returns the encryption algorithm.
203222 * <p>Note: Standard name is returned instead of the specified one
@@ -209,15 +228,15 @@ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
209228 * @return the encryption algorithm name.
210229 */
211230 public String getAlgName () {
212- return this . algid .getName ();
231+ return algid == null ? params . getAlgorithm () : algid .getName ();
213232 }
214233
215234 /**
216235 * Returns the algorithm parameters used by the encryption algorithm.
217236 * @return the algorithm parameters.
218237 */
219238 public AlgorithmParameters getAlgParameters () {
220- return this . algid .getParameters ();
239+ return algid == null ? params : algid .getParameters ();
221240 }
222241
223242 /**
@@ -252,14 +271,13 @@ public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
252271 byte [] encoded ;
253272 try {
254273 encoded = cipher .doFinal (encryptedData );
255- checkPKCS8Encoding (encoded );
274+ return pkcs8EncodingToSpec (encoded );
256275 } catch (GeneralSecurityException |
257276 IOException |
258277 IllegalStateException ex ) {
259278 throw new InvalidKeySpecException (
260279 "Cannot retrieve the PKCS8EncodedKeySpec" , ex );
261280 }
262- return new PKCS8EncodedKeySpec (encoded , keyAlg );
263281 }
264282
265283 private PKCS8EncodedKeySpec getKeySpecImpl (Key decryptKey ,
@@ -270,21 +288,20 @@ private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
270288 try {
271289 if (provider == null ) {
272290 // use the most preferred one
273- c = Cipher .getInstance (algid . getName ());
291+ c = Cipher .getInstance (getAlgName ());
274292 } else {
275- c = Cipher .getInstance (algid . getName (), provider );
293+ c = Cipher .getInstance (getAlgName (), provider );
276294 }
277- c .init (Cipher .DECRYPT_MODE , decryptKey , algid . getParameters ());
295+ c .init (Cipher .DECRYPT_MODE , decryptKey , getAlgParameters ());
278296 encoded = c .doFinal (encryptedData );
279- checkPKCS8Encoding (encoded );
297+ return pkcs8EncodingToSpec (encoded );
280298 } catch (NoSuchAlgorithmException nsae ) {
281299 // rethrow
282300 throw nsae ;
283301 } catch (GeneralSecurityException | IOException ex ) {
284302 throw new InvalidKeyException (
285303 "Cannot retrieve the PKCS8EncodedKeySpec" , ex );
286304 }
287- return new PKCS8EncodedKeySpec (encoded , keyAlg );
288305 }
289306
290307 /**
@@ -388,14 +405,23 @@ public byte[] getEncoded() throws IOException {
388405 DerOutputStream tmp = new DerOutputStream ();
389406
390407 // encode encryption algorithm
391- algid .encode (tmp );
408+ if (algid != null ) {
409+ algid .encode (tmp );
410+ } else {
411+ try {
412+ // Let's hope params has been initialized by now.
413+ AlgorithmId .get (params ).encode (tmp );
414+ } catch (Exception e ) {
415+ throw new IOException ("not initialized" , e );
416+ }
417+ }
392418
393419 // encode encrypted data
394420 tmp .putOctetString (encryptedData );
395421
396422 // wrap everything into a SEQUENCE
397423 out .write (DerValue .tag_Sequence , tmp );
398- this . encoded = out .toByteArray ();
424+ return out .toByteArray ();
399425 }
400426 return this .encoded .clone ();
401427 }
@@ -409,7 +435,7 @@ private static void checkTag(DerValue val, byte tag, String valName)
409435 }
410436
411437 @ SuppressWarnings ("fallthrough" )
412- private void checkPKCS8Encoding (byte [] encodedKey )
438+ private static PKCS8EncodedKeySpec pkcs8EncodingToSpec (byte [] encodedKey )
413439 throws IOException {
414440 DerInputStream in = new DerInputStream (encodedKey );
415441 DerValue [] values = in .getSequence (3 );
@@ -420,9 +446,9 @@ private void checkPKCS8Encoding(byte[] encodedKey)
420446 /* fall through */
421447 case 3 :
422448 checkTag (values [0 ], DerValue .tag_Integer , "version" );
423- keyAlg = AlgorithmId .parse (values [1 ]).getName ();
449+ String keyAlg = AlgorithmId .parse (values [1 ]).getName ();
424450 checkTag (values [2 ], DerValue .tag_OctetString , "privateKey" );
425- break ;
451+ return new PKCS8EncodedKeySpec ( encodedKey , keyAlg ) ;
426452 default :
427453 throw new IOException ("invalid key encoding" );
428454 }
0 commit comments