2017-08-14 3 views
0

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

Antwort

0

Mit gradle Abhängigkeit

compile group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '4.41.1' 

Bibliothek Ich bin in der Lage, das Problem zu beheben und melden JWT mit AndroidKeyStoreRSAPrivateKey

Hier RSASSASigner Konstruktor die PrivateKey nimmt ab Android KeyStore und dieser Unterzeichner werden zum Signieren von JWSObject verwendet.

Bei der Suche nach der Lösung habe ich nicht viele Informationen zu diesem Thema im Web gefunden, also hier eine Lösung zum Signieren von JWT mit PrivateKey von android Fingerprint API. Dank pedrofb für Sie :)

@RequiresApi(api = Build.VERSION_CODES.M) 
private String createJWT(){ 
    RSASSASigner signer = new RSASSASigner(BiometricHelper.getPrivateKey()); 
    JSONObject message = new JSONObject(); 
    message.put("client_id",mConfiguration.getClientID()); 

    JWSObject jwsObject = new JWSObject(
      new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(BiometricHelper.getKid()) 
      .customParam("auth_type","touchid").build(),new Payload(message)); 
    try { 
     jwsObject.sign(signer); 
    } catch (JOSEException e) { 
     e.printStackTrace(); 
    } 

    String jwt = jwsObject.serialize(); 

    Log.d("JWT============","\n"+jwt); 

    return jwt; 
} 

helfen Während dieser Sache arbeiten ich auf einige Fehler in Nimbus-JOSE-JWT ältere Version Danke https://bitbucket.org/connect2id/nimbus-jose-jwt/issues/169/android-m-support

1

Sie einen Schlüssel für die Verschlüsselung erstellt haben, nicht nur für die Unterzeichnung. Ändern

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()); 

Mit

mKeyPairGenerator.initialize(
     new KeyGenParameterSpec.Builder(
        KEY_NAME, 
        KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 
        .setDigests(KeyProperties.DIGEST_SHA256) 
        .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)) 
        .build()); 
+0

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

+1

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

+0

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

Verwandte Themen