Ich habe einige Ansprüche und ich möchte JWT erstellen und signieren mit einem PrivateKey in Fingerprint API erstellt.Sign JWT mit PrivateKey von android Fingerprint API
Dies ist JWT Anspruch -
Header:
{
"alg": "RS256”,
“kid”: “ABCDEDFkjsdfjaldfkjg”,
“auth_type” : “fingerprint”/"pin"
}
Payload:
{
“client_id”:”XXXXX-YYYYYY-ZZZZZZ”
}
Erstellen KeyPair für Fingerabdruck -
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.util.Log;
import com.yourmobileid.mobileid.library.common.MIDCommons;
import org.jose4j.base64url.Base64;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.RSAKeyGenParameterSpec;
@RequiresApi(api = Build.VERSION_CODES.M)
public class BiometricHelper {
public static final String KEY_NAME = "my_key";
static KeyPairGenerator mKeyPairGenerator;
private static String mKid;
private static KeyStore keyStore;
public static void init() {
try {
mKeyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("Failed to get an instance of KeyPairGenerator", e);
}
mKid = MIDCommons.generateRandomString();
keyStore = null;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException e) {
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
createKeyPair();
}
/**
* Generates an asymmetric key pair in the Android Keystore. Every use of the private key must
* be authorized by the user authenticating with fingerprint. Public key use is unrestricted.
*/
public static void createKeyPair() {
try {
mKeyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(
KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.build());
mKeyPairGenerator.generateKeyPair();
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
}
public static PrivateKey getPrivateKey() {
PrivateKey privateKey = null;
try {
keyStore.load(null);
privateKey = (PrivateKey) keyStore.getKey(KEY_NAME, null);
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return privateKey;
}
public static PublicKey getPublicKey() {
PublicKey publicKey = null;
try {
keyStore.load(null);
publicKey = keyStore.getCertificate(KEY_NAME).getPublicKey();
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return publicKey;
}
public static KeyStore getKeyStore(){
return keyStore;
}
public static String getPublicKeyStr() {
StringBuilder publicKey = new StringBuilder("-----BEGIN PUBLIC KEY-----\n");
publicKey.append(Base64.encode((getPublicKey().getEncoded())).replace("==",""));
publicKey.append("\n-----END PUBLIC KEY-----");
Log.d("Key==","\n"+publicKey);
return publicKey.toString();
}
public static String getKid() {
Log.d("mKid==","\n"+mKid);
return mKid;
}
}
Und auf diese Weise die Schaffung JWT -
@RequiresApi(api = Build.VERSION_CODES.M)
private String createJWT(){
JwtClaims claims = new JwtClaims();
claims.setClaim("client_id","”XXXXX-YYYYYY-ZZZZZZ”");
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setKey(BiometricHelper.getPrivateKey());
jws.setKeyIdHeaderValue(BiometricHelper.getKid());
jws.setHeader("auth_type","fingerprint");
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
String jwt = null;
try {
jwt = jws.getCompactSerialization();
} catch (JoseException e) {
e.printStackTrace();
}
System.out.println("JWT: " + jwt);
return jwt;
}
Wenn ich dies tue es immer bin -
W/System.err: org.jose4j.lang.InvalidKeyException: The given key (algorithm=RSA) is not valid for SHA256withRSA
W/System.err: at org.jose4j.jws.BaseSignatureAlgorithm.initForSign(BaseSignatureAlgorithm.java:97)
W/System.err: at org.jose4j.jws.BaseSignatureAlgorithm.sign(BaseSignatureAlgorithm.java:68)
W/System.err: at org.jose4j.jws.JsonWebSignature.sign(JsonWebSignature.java:101)
Ich habe viele andere Wege versucht, JWT mit PrivateKey zu signieren, bisher habe ich keine Lösung gefunden.
Jede Hilfe ist
geschätzt
für Ihre Hilfe @pedrofb berichtet kam. Ja, es ist sinnvoll KeyProperties zu ändern. PURPOSE_SIGN von KeyProperties.PURPOSE_ENCRYPT, aber ich habe immer noch Probleme mit . ClassCastException: android.security.keystore.AndroidKeyStoreRSAPrivateKey kann nicht in java.security.interfaces.RSAPrivateKey umgewandelt werden – Manisha
Könnten Sie den neuen Stack-Trace veröffentlichen? Haben Sie überprüft, dass jose4j mit Android Keystore kompatibel ist? Private Schlüssel sind gegen Extraktion geschützt. Wenn die Bibliothek versucht, sie zu manipulieren, wird sie fehlschlagen. – pedrofb
Vielen Dank, dass Ihr Kommentar mir geholfen hat, als ich nach jose4j gesucht habe, das mit Android Keystore kompatibel ist. Ich habe herausgefunden, dass sie Bug haben, und es wurde in next.https behoben: http://bitbucket.org/b_c/jose4j/pull-requests/8/ fix-for-android-60-Marshmallow/diff – Manisha