Make KeyType compatible with Android Keystore (#586)

* Make KeyType compatible with Android Keystore

Android Keystore private keys do not implement PrivateKey since the
raw key material is not available to applications.

With this commit, sshj's KeyType correctly detects the algorithm
associated with Android Keystore keys, which makes them usable for SSH
authentication.

* Extract RSA, DSA, ECDSA and EC into constants

* Fix license lint issue

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
This commit is contained in:
Fabian Henneke
2020-05-28 16:09:43 +02:00
committed by GitHub
parent dfdc464e08
commit 4e802cec86
12 changed files with 63 additions and 23 deletions

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.common;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.secg.SecgUtils;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
@@ -87,7 +88,7 @@ class ECDSAVariationsAdapter {
ECPoint p = new ECPoint(bigX, bigY);
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(p, ecCurveSpec);
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
KeyFactory keyFactory = KeyFactory.getInstance(KeyAlgorithm.ECDSA);
return keyFactory.generatePublic(publicKeySpec);
} catch (Exception ex) {
throw new GeneralSecurityException(ex);
@@ -103,7 +104,7 @@ class ECDSAVariationsAdapter {
}
static boolean isECKeyWithFieldSize(Key key, int fieldSize) {
return "ECDSA".equals(key.getAlgorithm())
return (KeyAlgorithm.ECDSA.equals(key.getAlgorithm()) || KeyAlgorithm.EC_KEYSTORE.equals(key.getAlgorithm()))
&& fieldSizeFromKey((ECKey) key) == fieldSize;
}

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.common;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.signature.Ed25519PublicKey;
import com.hierynomus.sshj.userauth.certificate.Certificate;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
@@ -30,9 +31,7 @@ import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
@@ -53,7 +52,7 @@ public enum KeyType {
} catch (Buffer.BufferException be) {
throw new GeneralSecurityException(be);
}
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA);
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
}
@@ -66,7 +65,7 @@ public enum KeyType {
@Override
protected boolean isMyType(Key key) {
return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey);
return KeyAlgorithm.RSA.equals(key.getAlgorithm());
}
},
@@ -84,7 +83,7 @@ public enum KeyType {
} catch (Buffer.BufferException be) {
throw new GeneralSecurityException(be);
}
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.DSA);
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
}
@@ -99,7 +98,7 @@ public enum KeyType {
@Override
protected boolean isMyType(Key key) {
return (key instanceof DSAPublicKey || key instanceof DSAPrivateKey);
return KeyAlgorithm.DSA.equals(key.getAlgorithm());
}
},

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.transport.kex;
import com.hierynomus.sshj.common.KeyAlgorithm;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.transport.random.Random;
import org.bouncycastle.asn1.x9.X9ECParameters;
@@ -31,7 +32,7 @@ public class Curve25519DH extends DHBase {
private byte[] secretKey;
public Curve25519DH() {
super("ECDSA", "ECDH");
super(KeyAlgorithm.ECDSA, "ECDH");
}
@Override

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.transport.kex;
import com.hierynomus.sshj.common.KeyAlgorithm;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.transport.random.Random;
@@ -54,7 +55,7 @@ public class ECDH extends DHBase {
@Override
public void computeK(byte[] f) throws GeneralSecurityException {
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.EC_BC);
ECPublicKeySpec keySpec = new ECPublicKeySpec(getDecoded(f, ecParameterSpec.getCurve()), ecParameterSpec);
PublicKey yourPubKey = keyFactory.generatePublic(keySpec);
agreement.doPhase(yourPubKey, true);

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.transport.verification;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.transport.verification.KnownHostMatchers;
import net.schmizz.sshj.common.*;
import org.slf4j.Logger;
@@ -239,7 +240,7 @@ public class OpenSSHKnownHosts
final BigInteger e = new BigInteger(split[i++]);
final BigInteger n = new BigInteger(split[i++]);
try {
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA);
key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
} catch (Exception ex) {
log.error("Error reading entry `{}`, could not create key", line, ex);

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.userauth.keyprovider;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
import net.schmizz.sshj.common.Base64;
import net.schmizz.sshj.common.ByteArrayUtils;
@@ -140,7 +141,7 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
ASN1Data asn = new ASN1Data(data = decrypt(Base64.decode(sb.toString()), cipher, iv));
switch (type) {
case RSA: {
KeyFactory factory = KeyFactory.getInstance("RSA");
KeyFactory factory = KeyFactory.getInstance(KeyAlgorithm.RSA);
asn.readNext();
BigInteger modulus = asn.readNext();
BigInteger pubExp = asn.readNext();
@@ -150,7 +151,7 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
return new KeyPair(pubKey, prvKey);
}
case DSA: {
KeyFactory factory = KeyFactory.getInstance("DSA");
KeyFactory factory = KeyFactory.getInstance(KeyAlgorithm.DSA);
asn.readNext();
BigInteger p = asn.readNext();
BigInteger q = asn.readNext();

View File

@@ -15,6 +15,7 @@
*/
package net.schmizz.sshj.userauth.keyprovider;
import com.hierynomus.sshj.common.KeyAlgorithm;
import net.schmizz.sshj.common.Base64;
import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.userauth.password.PasswordUtils;
@@ -114,7 +115,7 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
final KeyFactory factory;
try {
factory = KeyFactory.getInstance("RSA");
factory = KeyFactory.getInstance(KeyAlgorithm.RSA);
} catch (NoSuchAlgorithmException s) {
throw new IOException(s.getMessage(), s);
}
@@ -141,7 +142,7 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
final KeyFactory factory;
try {
factory = KeyFactory.getInstance("DSA");
factory = KeyFactory.getInstance(KeyAlgorithm.DSA);
} catch (NoSuchAlgorithmException s) {
throw new IOException(s.getMessage(), s);
}