2626import javax .crypto .spec .IvParameterSpec ;
2727import javax .crypto .spec .PBEKeySpec ;
2828import javax .crypto .spec .SecretKeySpec ;
29+ import javax .security .auth .DestroyFailedException ;
30+ import javax .security .auth .Destroyable ;
2931
3032import de .ntcomputer .crypto .hash .HashCondenser ;
3133import net .i2p .crypto .eddsa .EdDSAEngine ;
3840import net .i2p .crypto .eddsa .spec .EdDSAPrivateKeySpec ;
3941import net .i2p .crypto .eddsa .spec .EdDSAPublicKeySpec ;
4042
41- public class Ed25519PrivateKey {
43+ public class Ed25519PrivateKey implements Destroyable {
4244 static final EdDSAParameterSpec P_SPEC = EdDSANamedCurveTable .getByName (EdDSANamedCurveTable .CURVE_ED25519_SHA512 );
4345 private static SecureRandom random = null ;
4446 private final EdDSAPrivateKey key ;
@@ -100,6 +102,11 @@ public static Ed25519PrivateKey loadFromString(String privateKeyString, char[] p
100102 throw new RuntimeException (e );
101103 } catch (BadPaddingException e ) {
102104 throw new InvalidKeyException ("the supplied private key is corrupted or the password is wrong" , e );
105+ } finally {
106+ try {
107+ key .destroy ();
108+ } catch (DestroyFailedException e ) {
109+ }
103110 }
104111 }
105112
@@ -127,7 +134,6 @@ public void saveAsFile(File privateKeyFile, char[] password) throws IllegalArgum
127134 public String saveAsString (char [] password ) throws IllegalArgumentException , NoSuchAlgorithmException , NoSuchPaddingException {
128135 byte [] salt = new byte [512 /8 ];
129136 random ().nextBytes (salt );
130- SecretKey key = deriveKey (salt , password );
131137 byte [] iv = new byte [128 /8 ];
132138 random ().nextBytes (iv );
133139 byte [] privateKeySeed = this .key .getSeed ();
@@ -136,13 +142,19 @@ public String saveAsString(char[] password) throws IllegalArgumentException, NoS
136142 byte [] encodedKey = new byte [256 /8 + 512 /8 ];
137143 System .arraycopy (privateKeySeed , 0 , encodedKey , 0 , 256 /8 );
138144 System .arraycopy (privateKeySeedHash , 0 , encodedKey , 256 /8 , 512 /8 );
145+ SecretKey key = deriveKey (salt , password );
139146 try {
140147 Cipher cipher = Cipher .getInstance ("AES/CBC/PKCS5Padding" );
141148 cipher .init (Cipher .ENCRYPT_MODE , key , new IvParameterSpec (iv ));
142149 byte [] encryptedKey = cipher .doFinal (encodedKey );
143150 return Utils .bytesToHex (salt ) + Utils .bytesToHex (iv ) + Utils .bytesToHex (encryptedKey );
144151 } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e ) {
145152 throw new RuntimeException (e );
153+ } finally {
154+ try {
155+ key .destroy ();
156+ } catch (DestroyFailedException e ) {
157+ }
146158 }
147159 }
148160
@@ -195,4 +207,14 @@ public void signToFile(File source, File signatureFile) throws IOException, Ille
195207 Files .write (signatureFile .toPath (), signature .getBytes (StandardCharsets .UTF_8 ));
196208 }
197209
210+ @ Override
211+ public void destroy () throws DestroyFailedException {
212+ this .key .destroy ();
213+ }
214+
215+ @ Override
216+ public boolean isDestroyed () {
217+ return this .key .isDestroyed ();
218+ }
219+
198220}
0 commit comments