mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Clear passphrase bytes after use (#609)
Mimics the behavior of `decrypt()` in `PKCS5KeyFile.java`.
This commit is contained in:
@@ -143,9 +143,12 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
|||||||
CharBuffer charBuffer = CharBuffer.wrap(pwdf.reqPassword(null));
|
CharBuffer charBuffer = CharBuffer.wrap(pwdf.reqPassword(null));
|
||||||
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
|
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
|
||||||
passphrase = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
|
passphrase = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
|
||||||
|
Arrays.fill(charBuffer.array(), '\u0000');
|
||||||
|
Arrays.fill(byteBuffer.array(), (byte) 0);
|
||||||
}
|
}
|
||||||
byte[] keyiv = new byte[48];
|
byte[] keyiv = new byte[48];
|
||||||
new BCrypt().pbkdf(passphrase, opts.readBytes(), opts.readUInt32AsInt(), keyiv);
|
new BCrypt().pbkdf(passphrase, opts.readBytes(), opts.readUInt32AsInt(), keyiv);
|
||||||
|
Arrays.fill(passphrase, (byte) 0);
|
||||||
byte[] key = Arrays.copyOfRange(keyiv, 0, 32);
|
byte[] key = Arrays.copyOfRange(keyiv, 0, 32);
|
||||||
byte[] iv = Arrays.copyOfRange(keyiv, 32, 48);
|
byte[] iv = Arrays.copyOfRange(keyiv, 32, 48);
|
||||||
cipher.init(Cipher.Mode.Decrypt, key, iv);
|
cipher.init(Cipher.Mode.Decrypt, key, iv);
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ import java.security.interfaces.RSAPublicKey;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
@@ -70,6 +67,44 @@ public class OpenSSHKeyFileTest {
|
|||||||
final char[] correctPassphrase = "test_passphrase".toCharArray();
|
final char[] correctPassphrase = "test_passphrase".toCharArray();
|
||||||
final char[] incorrectPassphrase = new char[]{' '};
|
final char[] incorrectPassphrase = new char[]{' '};
|
||||||
|
|
||||||
|
private static class WipeTrackingPasswordFinder implements PasswordFinder {
|
||||||
|
private int reqCounter = 0;
|
||||||
|
|
||||||
|
final private String password;
|
||||||
|
final private boolean withRetry;
|
||||||
|
final private ArrayList<char[]> toWipe = new ArrayList<>();
|
||||||
|
|
||||||
|
WipeTrackingPasswordFinder(String password, Boolean withRetry) {
|
||||||
|
this.password = password;
|
||||||
|
this.withRetry = withRetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] reqPassword(Resource<?> resource) {
|
||||||
|
char[] passwordChars;
|
||||||
|
if (withRetry && reqCounter < 3) {
|
||||||
|
reqCounter++;
|
||||||
|
// Return an incorrect password three times before returning the correct one.
|
||||||
|
passwordChars = (password + "incorrect").toCharArray();
|
||||||
|
} else {
|
||||||
|
passwordChars = password.toCharArray();
|
||||||
|
}
|
||||||
|
toWipe.add(passwordChars);
|
||||||
|
return passwordChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRetry(Resource<?> resource) {
|
||||||
|
return withRetry && reqCounter <= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertWiped() {
|
||||||
|
for (char[] passwordChars : toWipe) {
|
||||||
|
assertArrayEquals(new char[passwordChars.length], passwordChars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
final PasswordFinder onlyGivesWhenReady = new PasswordFinder() {
|
final PasswordFinder onlyGivesWhenReady = new PasswordFinder() {
|
||||||
@Override
|
@Override
|
||||||
public char[] reqPassword(Resource resource) {
|
public char[] reqPassword(Resource resource) {
|
||||||
@@ -249,27 +284,11 @@ public class OpenSSHKeyFileTest {
|
|||||||
|
|
||||||
private void checkOpenSSHKeyV1(String key, final String password, boolean withRetry) throws IOException {
|
private void checkOpenSSHKeyV1(String key, final String password, boolean withRetry) throws IOException {
|
||||||
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
||||||
keyFile.init(new File(key), new PasswordFinder() {
|
WipeTrackingPasswordFinder pwf = new WipeTrackingPasswordFinder(password, withRetry);
|
||||||
private int reqCounter = 0;
|
keyFile.init(new File(key), pwf);
|
||||||
|
|
||||||
@Override
|
|
||||||
public char[] reqPassword(Resource<?> resource) {
|
|
||||||
if (withRetry && reqCounter < 3) {
|
|
||||||
reqCounter++;
|
|
||||||
// Return an incorrect password three times before returning the correct one.
|
|
||||||
return (password + "incorrect").toCharArray();
|
|
||||||
} else {
|
|
||||||
return password.toCharArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldRetry(Resource<?> resource) {
|
|
||||||
return withRetry && reqCounter <= 3;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
PrivateKey aPrivate = keyFile.getPrivate();
|
PrivateKey aPrivate = keyFile.getPrivate();
|
||||||
assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA"));
|
assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA"));
|
||||||
|
pwf.assertWiped();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user