diff --git a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java index a2a5c2d4..b0dabaff 100644 --- a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java +++ b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java @@ -5,7 +5,7 @@ import java.util.Arrays; /** - * A {@link KeyPair} which can only reveal its type and content after it was decrypted using KeyPairDeferred{@link #decrypt(byte[])}. + * A {@link KeyPair} which can only reveal its type and content after it was decrypted using {@link com.jcraft.jsch.KeyPairDeferred#decrypt(byte[])}. * This is needed for openssh-v1-private-key format. */ public class KeyPairDeferred extends KeyPair { @@ -72,62 +72,62 @@ void generate(int key_size) throws JSchException { @Override byte[] getBegin() { - return delegate.getBegin(); + return requireDecrypted(delegate).getBegin(); } @Override byte[] getEnd() { - return delegate.getEnd(); + return requireDecrypted(delegate).getEnd(); } @Override int getKeySize() { - return delegate.getKeySize(); + return requireDecrypted(delegate).getKeySize(); } @Override public byte[] getSignature(byte[] data) { - return delegate.getSignature(data); + return requireDecrypted(delegate).getSignature(data); } @Override public byte[] getSignature(byte[] data, String alg) { - return delegate.getSignature(data, alg); + return requireDecrypted(delegate).getSignature(data, alg); } @Override public Signature getVerifier() { - return delegate.getVerifier(); + return requireDecrypted(delegate).getVerifier(); } @Override public Signature getVerifier(String alg) { - return delegate.getVerifier(alg); + return requireDecrypted(delegate).getVerifier(alg); } @Override public byte[] forSSHAgent() throws JSchException { - return delegate.forSSHAgent(); + return requireDecrypted(delegate).forSSHAgent(); } @Override byte[] getPrivateKey() { - return delegate.getPrivateKey(); + return requireDecrypted(delegate).getPrivateKey(); } @Override byte[] getKeyTypeName() { - return delegate.getKeyTypeName(); + return requireDecrypted(delegate).getKeyTypeName(); } @Override public int getKeyType() { - return delegate.getKeyType(); + return requireDecrypted(delegate).getKeyType(); } @Override boolean parse(byte[] data) { - return delegate.parse(data); + return requireDecrypted(delegate).parse(data); } @Override @@ -137,16 +137,22 @@ public byte[] getPublicKeyBlob() { @Override public String getPublicKeyComment() { - return delegate.getPublicKeyComment(); + return requireDecrypted(delegate).getPublicKeyComment(); } @Override public String getFingerPrint() { - return delegate.getFingerPrint(); + return requireDecrypted(delegate).getFingerPrint(); } @Override public boolean isEncrypted() { return delegate != null ? delegate.isEncrypted() : super.isEncrypted(); } + + private T requireDecrypted(T obj) { + if (obj == null) + throw new IllegalStateException("encrypted key has not been decrypted yet."); + return obj; + } } diff --git a/src/test/java/com/jcraft/jsch/KeyPairTest.java b/src/test/java/com/jcraft/jsch/KeyPairTest.java index 296c3a85..8687e9a1 100644 --- a/src/test/java/com/jcraft/jsch/KeyPairTest.java +++ b/src/test/java/com/jcraft/jsch/KeyPairTest.java @@ -11,15 +11,16 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertTrue; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.*; class KeyPairTest { - @TempDir public Path tmpDir; + @TempDir + public Path tmpDir; @BeforeAll static void init() { @@ -41,21 +42,20 @@ static Stream keyArgs() { // encrypted dsa Arguments.of("encrypted_openssh_private_key_dsa", "secret123", "ssh-dss"), // ecdsa EC private key format - Arguments.of("docker/id_ecdsa256", null, null), // - Arguments.of("docker/id_ecdsa384", null, null), // - Arguments.of("docker/id_ecdsa521", null, null), - Arguments.of("docker/ssh_host_ecdsa256_key", null, null), - Arguments.of("docker/ssh_host_ecdsa384_key", null, null), - Arguments.of("docker/ssh_host_ecdsa521_key", null, null), + Arguments.of("docker/id_ecdsa256", null, "ecdsa-sha2-nistp256"), // + Arguments.of("docker/id_ecdsa384", null, "ecdsa-sha2-nistp384"), // + Arguments.of("docker/id_ecdsa521", null, "ecdsa-sha2-nistp521"), + Arguments.of("docker/ssh_host_ecdsa256_key", null, "ecdsa-sha2-nistp256"), + Arguments.of("docker/ssh_host_ecdsa384_key", null, "ecdsa-sha2-nistp384"), + Arguments.of("docker/ssh_host_ecdsa521_key", null, "ecdsa-sha2-nistp521"), // encrypted ecdsa - Arguments.of("encrypted_openssh_private_key_ecdsa", "secret123", null) - + Arguments.of("encrypted_openssh_private_key_ecdsa", "secret123", "ecdsa-sha2-nistp256") ); } @ParameterizedTest @MethodSource("keyArgs") - void loadKey(String path, String password, String publicKeyType) throws URISyntaxException, JSchException { + void loadKey(String path, String password, String keyType) throws URISyntaxException, JSchException { final JSch jSch = new JSch(); final String prvkey = Paths.get(ClassLoader.getSystemResource(path).toURI()).toFile().getAbsolutePath(); assertTrue(new File(prvkey).exists()); @@ -66,6 +66,7 @@ void loadKey(String path, String password, String publicKeyType) throws URISynta jSch.addIdentity(prvkey); } }); + assertEquals(keyType, jSch.getIdentityRepository().getIdentities().get(0).getAlgName()); } @Test @@ -86,4 +87,16 @@ void genKeypairEncrypted() { }); } + @Test + void loadAndAcessEncryptedKeyWithoutPassword() throws URISyntaxException, JSchException { + final JSch jSch = new JSch(); + final String prvkey = Paths.get(ClassLoader.getSystemResource("encrypted_openssh_private_key_dsa").toURI()).toFile().getAbsolutePath(); + assertTrue(new File(prvkey).exists()); + jSch.addIdentity(prvkey); + + assertThrows(IllegalStateException.class, () -> { + jSch.getIdentityRepository().getIdentities().get(0).getAlgName(); + }); + } + }