mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 23:30:55 +03:00
Update OpenSSH Key V1 parsing using CRT information for RSA Private Keys (#726)
* Update OpenSSH Key V1 parsing using CRT information for RSA Private Keys * Remove unndeeded BC call. Signed-off-by: Jeroen van Erp <jeroen@hierynomus.com> Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
This commit is contained in:
@@ -45,7 +45,7 @@ import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.*;
|
||||
import java.security.spec.ECPrivateKeySpec;
|
||||
import java.security.spec.RSAPrivateKeySpec;
|
||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -245,13 +245,9 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
kp = new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName("Ed25519"))));
|
||||
break;
|
||||
case RSA:
|
||||
BigInteger n = keyBuffer.readMPInt(); // Modulus
|
||||
keyBuffer.readMPInt(); // Public Exponent
|
||||
BigInteger d = keyBuffer.readMPInt(); // Private Exponent
|
||||
keyBuffer.readMPInt(); // iqmp (q^-1 mod p)
|
||||
keyBuffer.readMPInt(); // p (Prime 1)
|
||||
keyBuffer.readMPInt(); // q (Prime 2)
|
||||
kp = new KeyPair(publicKey, SecurityUtils.getKeyFactory(KeyAlgorithm.RSA).generatePrivate(new RSAPrivateKeySpec(n, d)));
|
||||
final RSAPrivateCrtKeySpec rsaPrivateCrtKeySpec = readRsaPrivateKeySpec(keyBuffer);
|
||||
final PrivateKey privateKey = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA).generatePrivate(rsaPrivateCrtKeySpec);
|
||||
kp = new KeyPair(publicKey, privateKey);
|
||||
break;
|
||||
case ECDSA256:
|
||||
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-256"));
|
||||
@@ -284,6 +280,35 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
ECNamedCurveSpec ecCurveSpec = new ECNamedCurveSpec(name, ecParams.getCurve(), ecParams.getG(), ecParams.getN());
|
||||
ECPrivateKeySpec pks = new ECPrivateKeySpec(s, ecCurveSpec);
|
||||
return SecurityUtils.getKeyFactory(KeyAlgorithm.ECDSA).generatePrivate(pks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read RSA Private CRT Key Spec according to OpenSSH sshkey_private_deserialize in sshkey.c
|
||||
*
|
||||
* @param buffer Buffer
|
||||
* @return RSA Private CRT Key Specification
|
||||
* @throws Buffer.BufferException Thrown on failure to read from buffer
|
||||
*/
|
||||
private RSAPrivateCrtKeySpec readRsaPrivateKeySpec(final PlainBuffer buffer) throws Buffer.BufferException {
|
||||
final BigInteger modulus = buffer.readMPInt();
|
||||
final BigInteger publicExponent = buffer.readMPInt();
|
||||
final BigInteger privateExponent = buffer.readMPInt();
|
||||
final BigInteger crtCoefficient = buffer.readMPInt(); // iqmp (q^-1 mod p)
|
||||
final BigInteger primeP = buffer.readMPInt();
|
||||
final BigInteger primeQ = buffer.readMPInt();
|
||||
|
||||
// Calculate Prime Exponent P and Prime Exponent Q according to RFC 8017 Section 3.2
|
||||
final BigInteger primeExponentP = privateExponent.remainder(primeP.subtract(BigInteger.ONE));
|
||||
final BigInteger primeExponentQ = privateExponent.remainder(primeQ.subtract(BigInteger.ONE));
|
||||
return new RSAPrivateCrtKeySpec(
|
||||
modulus,
|
||||
publicExponent,
|
||||
privateExponent,
|
||||
primeP,
|
||||
primeQ,
|
||||
primeExponentP,
|
||||
primeExponentQ,
|
||||
crtCoefficient
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPrivateCrtKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
@@ -103,7 +104,7 @@ public class OpenSSHKeyFileTest {
|
||||
assertArrayEquals(new char[passwordChars.length], passwordChars);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
final PasswordFinder onlyGivesWhenReady = new PasswordFinder() {
|
||||
@Override
|
||||
@@ -187,7 +188,7 @@ public class OpenSSHKeyFileTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHaveCorrectFingerprintForECDSA256() throws IOException, GeneralSecurityException {
|
||||
public void shouldHaveCorrectFingerprintForECDSA256() throws IOException {
|
||||
OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
|
||||
keyFile.init(new File("src/test/resources/keytypes/test_ecdsa_nistp256"));
|
||||
String expected = "256 MD5:53:ae:db:ed:8f:2d:02:d4:d5:6c:24:bc:a4:66:88:79 root@itgcpkerberosstack-cbgateway-0-20151117031915 (ECDSA)\n";
|
||||
@@ -197,7 +198,7 @@ public class OpenSSHKeyFileTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHaveCorrectFingerprintForECDSA384() throws IOException, GeneralSecurityException {
|
||||
public void shouldHaveCorrectFingerprintForECDSA384() throws IOException {
|
||||
OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
|
||||
keyFile.init(new File("src/test/resources/keytypes/test_ecdsa_nistp384"));
|
||||
String expected = "384 MD5:ee:9b:82:d1:47:01:16:1b:27:da:f5:27:fd:b2:eb:e2";
|
||||
@@ -207,7 +208,7 @@ public class OpenSSHKeyFileTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHaveCorrectFingerprintForECDSA521() throws IOException, GeneralSecurityException {
|
||||
public void shouldHaveCorrectFingerprintForECDSA521() throws IOException {
|
||||
OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
|
||||
keyFile.init(new File("src/test/resources/keytypes/test_ecdsa_nistp521"));
|
||||
String expected = "521 MD5:22:e2:f4:3c:61:ae:e9:85:a1:4d:d9:6c:13:aa:eb:00";
|
||||
@@ -274,6 +275,35 @@ public class OpenSSHKeyFileTest {
|
||||
assertThat(aPrivate.getAlgorithm(), equalTo("RSA"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadRSAPrivateCrtKeyAsOpenSSHV1() throws IOException {
|
||||
final OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
||||
keyFile.init(new File("src/test/resources/keyformats/rsa_opensshv1"));
|
||||
final PrivateKey privateKey = keyFile.getPrivate();
|
||||
final PublicKey publicKey = keyFile.getPublic();
|
||||
|
||||
assertTrue(publicKey instanceof RSAPublicKey);
|
||||
final RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
|
||||
|
||||
assertTrue(privateKey instanceof RSAPrivateCrtKey);
|
||||
final RSAPrivateCrtKey rsaPrivateCrtKey = (RSAPrivateCrtKey) privateKey;
|
||||
|
||||
assertEquals("Public Key Exponent not matched", rsaPublicKey.getPublicExponent(), rsaPrivateCrtKey.getPublicExponent());
|
||||
assertEquals("Public Key Modulus not matched", rsaPublicKey.getModulus(), rsaPrivateCrtKey.getModulus());
|
||||
|
||||
final BigInteger privateExponent = rsaPrivateCrtKey.getPrivateExponent();
|
||||
|
||||
final BigInteger expectedPrimeExponentP = privateExponent.mod(rsaPrivateCrtKey.getPrimeP().subtract(BigInteger.ONE));
|
||||
assertEquals("Prime Exponent P not matched", expectedPrimeExponentP, rsaPrivateCrtKey.getPrimeExponentP());
|
||||
|
||||
final BigInteger expectedPrimeExponentQ = privateExponent.mod(rsaPrivateCrtKey.getPrimeQ().subtract(BigInteger.ONE));
|
||||
assertEquals("Prime Exponent Q not matched", expectedPrimeExponentQ, rsaPrivateCrtKey.getPrimeExponentQ());
|
||||
|
||||
|
||||
final BigInteger expectedCoefficient = rsaPrivateCrtKey.getPrimeQ().modInverse(rsaPrivateCrtKey.getPrimeP());
|
||||
assertEquals("Prime CRT Coefficient not matched", expectedCoefficient, rsaPrivateCrtKey.getCrtCoefficient());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadECDSAPrivateKeyAsOpenSSHV1() throws IOException {
|
||||
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
||||
|
||||
Reference in New Issue
Block a user