diff --git a/ChangeLog.md b/ChangeLog.md
index dee777b8..ddc53f68 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,9 @@
* [0.2.10](https://github.com/mwiede/jsch/releases/tag/jsch-0.2.10)
* Fix new Java 21 compiler warning: `possible 'this' escape before subclass is fully initialized`.
* Tweak OSGi bundle manifest to allow Log4j 3.
+ * [#362](https://github.com/mwiede/jsch/issues/362) fix PEM key parsing to work with windows line endings.
+ * [#361](https://github.com/mwiede/jsch/issues/361) guard against `UIKeyboardInteractive` implementations that include NULL elements in the `String[]` returned from `promptKeyboardInteractive()`.
+ * Add a default implmentation of the deprecated `decrypt()` method to the `Identity` interface that throws an `UnsupportedOperationException`.
* [0.2.9](https://github.com/mwiede/jsch/releases/tag/jsch-0.2.9)
* [#293](https://github.com/mwiede/jsch/issues/293) allow UserAuthNone to be extended.
* Make JGSS module optional.
diff --git a/pom.xml b/pom.xml
index 3fdd037d..654bea71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -156,15 +156,15 @@
test
- com.kohlschutter.junixsocket
- junixsocket-native-common
- ${junixsocket.version}
+ commons-io
+ commons-io
+ 2.13.0
test
- com.google.guava
- guava
- 32.1.1-jre
+ com.kohlschutter.junixsocket
+ junixsocket-native-common
+ ${junixsocket.version}
test
diff --git a/src/main/java/com/jcraft/jsch/AgentIdentity.java b/src/main/java/com/jcraft/jsch/AgentIdentity.java
index 2fe5a2bc..3f83e4fb 100644
--- a/src/main/java/com/jcraft/jsch/AgentIdentity.java
+++ b/src/main/java/com/jcraft/jsch/AgentIdentity.java
@@ -60,12 +60,6 @@ public byte[] getSignature(byte[] data, String alg) {
return agent.sign(blob, data, alg);
}
- @Override
- @Deprecated
- public boolean decrypt() {
- throw new RuntimeException("not implemented");
- }
-
@Override
public String getAlgName() {
return algname;
diff --git a/src/main/java/com/jcraft/jsch/Identity.java b/src/main/java/com/jcraft/jsch/Identity.java
index 5aee38c8..f27c36bb 100644
--- a/src/main/java/com/jcraft/jsch/Identity.java
+++ b/src/main/java/com/jcraft/jsch/Identity.java
@@ -83,22 +83,30 @@ public default byte[] getSignature(byte[] data, String alg) {
}
/**
+ * This method is deprecated and the default implmentation of this method will throw an
+ * {@link UnsupportedOperationException}.
+ *
* @deprecated The decryption should be done automatically in {@link #setPassphrase(byte[])}
+ * @return true
if the decryption is succeeded or this identity is not cyphered.
* @see #setPassphrase(byte[])
*/
@Deprecated
- public boolean decrypt();
+ public default boolean decrypt() {
+ throw new UnsupportedOperationException("not implemented");
+ }
/**
* Returns the name of the key algorithm.
*
- * @return "ssh-rsa" or "ssh-dss"
+ * @return the name of the key algorithm
*/
public String getAlgName();
/**
* Returns the name of this identity. It will be useful to identify this object in the
* {@link IdentityRepository}.
+ *
+ * @return the name of this identity
*/
public String getName();
diff --git a/src/main/java/com/jcraft/jsch/IdentityFile.java b/src/main/java/com/jcraft/jsch/IdentityFile.java
index 89555674..af55a0b4 100644
--- a/src/main/java/com/jcraft/jsch/IdentityFile.java
+++ b/src/main/java/com/jcraft/jsch/IdentityFile.java
@@ -45,7 +45,7 @@ static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey,
return new IdentityFile(name, kpair);
}
- private IdentityFile(String name, KeyPair kpair) throws JSchException {
+ private IdentityFile(String name, KeyPair kpair) {
this.identity = name;
this.kpair = kpair;
}
@@ -94,30 +94,21 @@ public byte[] getSignature(byte[] data, String alg) {
return kpair.getSignature(data, alg);
}
- /**
- * @deprecated This method should not be invoked.
- * @see #setPassphrase(byte[] passphrase)
- */
- @Override
- @Deprecated
- public boolean decrypt() {
- throw new RuntimeException("not implemented");
- }
-
/**
* Returns the name of the key algorithm.
*
- * @return "ssh-rsa" or "ssh-dss"
+ * @return the name of the key algorithm
*/
@Override
public String getAlgName() {
- byte[] name = kpair.getKeyTypeName();
- return Util.byte2str(name);
+ return kpair.getKeyTypeString();
}
/**
* Returns the name of this identity. It will be useful to identify this object in the
* {@link IdentityRepository}.
+ *
+ * @return the name of this identity
*/
@Override
public String getName() {
diff --git a/src/main/java/com/jcraft/jsch/KeyPair.java b/src/main/java/com/jcraft/jsch/KeyPair.java
index 7e29f888..041a4862 100644
--- a/src/main/java/com/jcraft/jsch/KeyPair.java
+++ b/src/main/java/com/jcraft/jsch/KeyPair.java
@@ -891,6 +891,7 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey
start = 0;
i = 0;
+ int xds = 0;
int _len = _buf.length;
while (i < _len) {
@@ -898,8 +899,10 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey
boolean xd = (_buf[i - 1] == '\r');
// ignore \n (or \r\n)
System.arraycopy(_buf, i + 1, _buf, i - (xd ? 1 : 0), _len - (i + 1));
- if (xd)
+ if (xd) {
_len--;
+ xds++;
+ }
_len--;
continue;
}
@@ -909,8 +912,8 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey
i++;
}
- if (i - start > 0)
- data = Util.fromBase64(_buf, start, i - start);
+ if (i - xds - start > 0)
+ data = Util.fromBase64(_buf, start, i - xds - start);
Util.bzero(_buf);
}
diff --git a/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
index c7aff920..cd5d5eda 100644
--- a/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
+++ b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
@@ -141,7 +141,7 @@ public boolean start(Session session) throws Exception {
if (_response != null) {
response = new byte[_response.length][];
for (int i = 0; i < _response.length; i++) {
- response[i] = Util.str2byte(_response[i]);
+ response[i] = _response[i] != null ? Util.str2byte(_response[i]) : Util.empty;
}
}
}
diff --git a/src/main/java/com/jcraft/jsch/UserAuthPassword.java b/src/main/java/com/jcraft/jsch/UserAuthPassword.java
index 6d75da94..111e0def 100644
--- a/src/main/java/com/jcraft/jsch/UserAuthPassword.java
+++ b/src/main/java/com/jcraft/jsch/UserAuthPassword.java
@@ -127,7 +127,7 @@ public boolean start(Session session) throws Exception {
throw new JSchAuthCancelException("password");
}
- byte[] newpassword = Util.str2byte(response[0]);
+ byte[] newpassword = response[0] != null ? Util.str2byte(response[0]) : Util.empty;
// send
// byte SSH_MSG_USERAUTH_REQUEST(50)
diff --git a/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java b/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java
index 0af63f77..508de07c 100644
--- a/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java
+++ b/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java
@@ -6,7 +6,6 @@
import com.github.valfirst.slf4jtest.LoggingEvent;
import com.github.valfirst.slf4jtest.TestLogger;
import com.github.valfirst.slf4jtest.TestLoggerFactory;
-import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -17,6 +16,7 @@
import java.util.List;
import java.util.Random;
import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.input.BoundedInputStream;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -209,7 +209,7 @@ private void doScp(Session session, boolean debugException) throws Exception {
byte[] buf = new byte[17];
is.read(buf, 0, 17);
sendAck(os);
- Files.copy(ByteStreams.limit(is, 100L * 1024L), out);
+ Files.copy(new BoundedInputStream(is, 100L * 1024L), out);
checkAck(is);
sendAck(os);
}
diff --git a/src/test/java/com/jcraft/jsch/KeyPairTest.java b/src/test/java/com/jcraft/jsch/KeyPairTest.java
index 9ab555a3..066382db 100644
--- a/src/test/java/com/jcraft/jsch/KeyPairTest.java
+++ b/src/test/java/com/jcraft/jsch/KeyPairTest.java
@@ -35,6 +35,8 @@ static Stream keyArgs() {
Arguments.of("docker/ssh_host_dsa_key", null, "ssh-dss"),
// encrypted dsa
Arguments.of("encrypted_openssh_private_key_dsa", "secret123", "ssh-dss"),
+ // unencrypted RSA with windows (\r\n) line endings
+ Arguments.of("issue362_rsa", null, "ssh-rsa"),
// ecdsa EC private key format
Arguments.of("docker/id_ecdsa256", null, "ecdsa-sha2-nistp256"), //
Arguments.of("docker/id_ecdsa384", null, "ecdsa-sha2-nistp384"), //
diff --git a/src/test/resources/docker/authorized_keys.KeyPairIT b/src/test/resources/docker/authorized_keys.KeyPairIT
index fc007f26..ac83da75 100644
--- a/src/test/resources/docker/authorized_keys.KeyPairIT
+++ b/src/test/resources/docker/authorized_keys.KeyPairIT
@@ -5,6 +5,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNVEfQu64p2GczvWj0AlncuNG+PzPd0jZ1/hfx/JDz
ssh-dss AAAAB3NzaC1kc3MAAACBAKCQzxCEIM7yb5fbSmuJCz/+v40WEbULx4JKCXBb7zmRtDtweBqUJXDM1bMjQ4VwGB1EkfMZJQR7rPrOAxfdMdCpkqgPR0+xlljZLVarSJHwt1KR9EudUjUdD2ZrPlvPlG1sAyvMVTK5KCx2QaS2Bn/gukxrvT7DkaqCFHg2P7rLAAAAFQCF+m0B12XxhF1P+3hF3ktGmfYpywAAAIBX+azef1TX90FwS7vyngCrdJsOYqWtj1zQ8MlrwrWL0jdbjcIG/0vcq1x84LTgs+hAPylDBCGGJa/td88kJ6jIUeWiebRUG0zEH8LM+nehQA5O6TuEV3U0Dg73I0Mb04ZzN2GqYqW+KwHdiaU5M8XQv3V/PCmY8d7R5WcMKKDCcQAAAIEAmy0FgQoaWyHdD84b7zD0YjziMsVELAbGWwdxNuNe6wtACcctCdIQigQYaC2HwGjlDKVMjQfd4RWArshg7p0PlEw7//HSgoVhwcBbDpmWGCS6TxSSQpDmdDgiVegERMYjo2BZoZQTuJIx/BhQggVISkELwZfsi1BnPC5Aecq7ILI= test
ssh-dss AAAAB3NzaC1kc3MAAACBAMKmaZwslPWE83wv+Ofl9oaMeOR03Yk0cyDc5fSAgjepXZQR5sps0KFORRufI6dLQHY4XLoyPc/Hr0ra+vY/l+p20cJVjQ07oosPU/d2eLdZ66rdjXCyrJPjFjnNJtumnBnJZqWGObKspnWk73vPOflReyGpUFe51PF1usur3uDLAAAAFQC3dSlxZZVNbvqjJpg8/oSMuG27/QAAAIEApkd3miYVc/Cl1QwdqwInIjby1yGNCfFsZALGBYc67lkd5lGBdNlL+fgi+BwC6UXu5OAqWB/b9OtvJR8NRcM77V252IER4t95t2ZdG66M1T5q1aOVL/ehPZFHf0oPXHJLcsybzqKFAtQj5hEbnrwJYW0fWi87C9LApplzPTVYQikAAACAUEu5tFmImzyQsUBMN/j1GWCCSVznjfRHkeGwx5koC0D2iK3mMphnF9avsoX2PrboEbGqy69JPCekKQiPPWxcQRTRqFS/ySkECJ5lJ2zJrW1whjLQEJbOq7WmusSML9UXCpNSwCqhJxPYx5a8Pq7lrrBP21jT/Z/A4m4c4wMkLXo= test
ssh-dss AAAAB3NzaC1kc3MAAACBAPmIBCP1AA8EiTL0VAdzau+1KuRmPkg+H2du4zt4ifhzEx4MscZ7cpBsUAM/EBC/ECWTHzDiWyFFuenvxDlfTi9XxySdOKM6XGLkY7oLsY1y5bShyLrycxDD7MRQ8HpUc9TPzE2PDH4Od6o98e+vdXP0+IDUZGbSuwEnaABX/1+ZAAAAFQDIB9KUd1/gnzM4s4FXCQb7zCnjVwAAAIBptrE9g/ooRnh4bOWiA3/StxbjMRmA9f9bJbM55CinL4yf/GdGmeBp6YjDBxDyk1oXmVJ2hLVXgW6kETbt+D01SouCTgLPlFwLFhqZQ+A4JQOKuLIBaM92hI7sAfTewkxbmAk/e1vyOeyfcQDhbncESzVBZrheXC1fTKv7O2PgbgAAAIBKhGEiNwKNA/pfYvkEbX90/jVoIEKZfqTk+PB2gbVMT98LWPaexrDwEGuCCK3KOtMncDai+0r1ujf1hzNJ4z43Z1n15tPvAIwQsObTL+eUQkVjHA8LXOq8n4yYyPidkjGzWcfBAm4Lm6vKkzFM3VRouQIHpWpjRl3wGTJZkOoH0Q== test
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDY+326Z0bUOn8kYUc399P2mr7Eh0E7Nc9zPrv80B05ykfmsCM053SiGYQgwP5aBzZk83PdWdYIK12U9eO5WzTwT2po9PrZT0AvsBGnU7MkzSSlXX79e9ELbGYNWV4DafT/VHxVwCuoctG7XKUorGA3ZHxGbhNWyo/+6LNwyCMcxfpjpCelJWn4MTwFqs0DVme4R2Sy+LaVg3Nv5Vbbi27cIbA+6Orit2ajDUUCHJvcQlpGrM6x9w0zbt4pUI6yHPCHIIqZEPzj1285GCF6ZQzi0TMEf4wHtA8fN1Xgn1vBw+IEkrAAnQUeTWOR1nc6CDFEGTlyYlIuz634I4BwfhBl test
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBcLHSACx0yr1S902vlRRnXA12YpaXIOkZUXoNFb01+CxQBgGpVTEVMuakLpIW/XcD9ltu+c6Czk5WnBKEoHNuI= test
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBPKyvhX/3Q32EEhZKF6s+fEzfQwabsSpXgFJ2LwpGxKFxzE2jw4Nvwe9W3YbPyrZU6K2MMA7p7ZdJwdDP/tQ9dhttOGGSkea9Cq4dcdgC9cdBuQ4aGb8crmY3Z5wc1dPxQ== test
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAG3XTlAFoQd4iIBt5KoTHJk46v1AdZSd+wfCSpc2/GCzHNGVqidrKCrypszpkQOW6vYG8riilyfF36rJa9ipjR+5gDApLIe/ix1Fknr8MU6nWoYv2+NBTsEcaS/VTeiUuMKftMtlO2wOaWFcbZBQUAlb3LDnpMyYKCqIXhhl4vqCxBukg== test
diff --git a/src/test/resources/issue362_rsa b/src/test/resources/issue362_rsa
new file mode 100644
index 00000000..0c0e41d8
--- /dev/null
+++ b/src/test/resources/issue362_rsa
@@ -0,0 +1,3 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA2Pt9umdG1Dp/JGFHN/fT9pq+xIdBOzXPcz67/NAdOcpH5rAjNOd0ohmEIMD+Wgc2ZPNz3VnWCCtdlPXjuVs08E9qaPT62U9AL7ARp1OzJM0kpV1+/XvRC2xmDVleA2n0/1R8VcArqHLRu1ylKKxgN2R8Rm4TVsqP/uizcMgjHMX6Y6QnpSVp+DE8BarNA1ZnuEdksvi2lYNzb+VW24tu3CGwPujq4rdmow1FAhyb3EJaRqzOsfcNM27eKVCOshzwhyCKmRD849dvORghemUM4tEzBH+MB7QPHzdV4J9bwcPiBJKwAJ0FHk1jkdZ3OggxRBk5cmJSLs+t+COAcH4QZQIDAQABAoIBAGcA5AuEEWyYJFkZ0Nwxyq6LgTn8VywLfGJiCo2WIfmYHA/X1666nXSCFmYSF+yW9exwYbVXezI/m9ol7CfGs1fM61/Nw/M7GuZId+jt4+H5fIb/3lPo3jDFEaEOpoGKYCKBcdCnPFJnx0ZhUYoAYmCJVDF++bE+0aKZxu0oJPr35Lda1hBeCfrb8fDReAAU71jIoOGyuSyOXlCVyT+OmBhVme0u2xDpdY8cd5t9YueTK7BFNjNt3sJOI4L+2wRskNwxqHCrECtuOXmzEyza7vqo8cjRGSx1HZfqhoKgiRpRkRmSi8p+X1+DZOVZuCxc3BTZ7WrPgVZhu7u9hsISKyECgYEA+C9ajUNsx7Hx9gOg6Zvr+zV461PjKI/0n9g0DTZ5RHdcAfeNs3ugmsiDK6b9SayUW08EVyveJ1OJjT/NPvdP0/KhCAjUt+kN0j9f9CPdHKEWoboDca8u67dayOAhC10mNhoAp3tFQryfgpb678GIzqnXkVjGgyWC/8Z81AN7uAkCgYEA39CcJAUVMc6FigTwoMOkdOgNK6qCxAxkNBTdfB/cBBtG3h8g49n0u/fAMjkfL6awdl53j3jVCP4pUZgSSqArLb0aGo84G2vP92iN3d3j/kPiox22w8KG2XR7tHLWcc+CFfk8mdiKdPFxaWVQaYJ6htGq9LGqY3sw5lVzmk0wlH0CgYEAuWim/WGhoo4NdPzA+cTCRqlr7GJ/EY558fBS8ov/jGafFdkawztYgEnLtJDMKH4FVzFwzK65CCggWqWPb7rSqERaiOYQBFTXPnqZ9InWZczyW1/bstJs+yu/ZtIJ3bN5GHHUi0pMM882Wxjv3q12xu2bXbo0k0Uy2GIwXzM6+gECgYBDByur0eXeC7aMdhxGWTEoXdKL8D3HTtq3ikQmhzgR9sVLglEMS9rybCkgIWFImQgh+vqdehd64Pso130q4jrsMMTfjWLFO42Fz8ck2e4M2PHH3f89M0XFXBAsI3Q7k2SnBgRzIpmcmi5X3SKu5oehVqt3KroXnu4vHQpI/LL+1QKBgD3zxf795zFXw53iZXtKkzYNQhEMVRzbx6dQE+tguB0YCb2vPvYaxfejg/02hCQ4twIMuMK18v0Y9W7E34C0m++lP8UbnHdR0Dsg9ryH7OlUMp4662060HWDnDy79swB/Nnk9dxf+BoPIXGny84bEpk6cLoiHuL6TRpQhuJ292DW
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/resources/issue362_rsa.pub b/src/test/resources/issue362_rsa.pub
new file mode 100644
index 00000000..d378cbe0
--- /dev/null
+++ b/src/test/resources/issue362_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDY+326Z0bUOn8kYUc399P2mr7Eh0E7Nc9zPrv80B05ykfmsCM053SiGYQgwP5aBzZk83PdWdYIK12U9eO5WzTwT2po9PrZT0AvsBGnU7MkzSSlXX79e9ELbGYNWV4DafT/VHxVwCuoctG7XKUorGA3ZHxGbhNWyo/+6LNwyCMcxfpjpCelJWn4MTwFqs0DVme4R2Sy+LaVg3Nv5Vbbi27cIbA+6Orit2ajDUUCHJvcQlpGrM6x9w0zbt4pUI6yHPCHIIqZEPzj1285GCF6ZQzi0TMEf4wHtA8fN1Xgn1vBw+IEkrAAnQUeTWOR1nc6CDFEGTlyYlIuz634I4BwfhBl test