Supposons que j'ai le JWK suivant comme corps désérialisé de certains JWS (RFC7515), où le module n est partiellement omis à des fins d'affichage

{
   "kty": "RSA",
   "e": "AQAB",
   "kid": "KAgNpWbRyy9Mf2rikl498LThMrvkbZWHVSQOBC4VHU4",
   "n": "llWmHF8XA2KNLdmxOP3kxD9OY76p0Sr37j..."
}

Et l'en-tête JWS spécifie à la fois les champs alg et kid requis pour la vérification de la signature.

Comment puis-je construire une clé publique RSA à partir de ce JWK afin de pouvoir vérifier la signature? Après avoir examiné certains liés questions , j'ai l'implémentation Java suivante qui tente de créer une clé publique RSA à partir de {{X1 }} et e dans les champs JWK

public void someMethod(){
    String exjws ="eyJhbGciOiJSUzI1NiIsImtpZCI6IktBZ05wV2JSeXk5TWYycmlrbDQ5OExUaE1ydmtiWldIVlNRT0JDNFZIVTQiL"
        + "CJodG0iOiJwb3N0IiwiaHR1IjoiL3R4IiwidHMiOjE2MDM4MDA3ODN9.eyJjYXBhYmlsaXRpZXMiOltdLCJjbGllbnQiOnsia2V5Ijp7Imp3ayI6eyJrdHkiOiJSU0EiLCJ"
        + "hbGciOiJSUzI1NiIsImUiOiJBUUFCIiwia2lkIjoiS0FnTnBXYlJ5eTlNZjJyaW"
        + "tsNDk4TFRoTXJ2a2JaV0hWU1FPQkM0VkhVNCIsIm4iOiJsbFdtSEY4WEEyS05MZG14T1Aza3hEOU9ZNzZwMFNyMzdqZmh6OTRhOTN4bTJGTnFvU1BjUlpBUGQwbHFEUzhO"
        + "M1VpYTUzZEIyM1o1OU93WTRicE1fVmY4R0p2dnB0TFdueG8xUHlobVByIC0gZWNkU0NSUWRUY19aY01GNGhSVjQ4cXFsdnVEMG1xdGNEYklrU0JEdmNjSm1aSHdmVHBESG"
        + "luVDh0dHZjVlA4VmtBTUFxNGtWYXp4T3BNb0lSc295RXBfZUNlNXBTd3FIbzBkYUNXTktSI"
        + "C0gRXBLbTZOaU90ZWRGNE91bXQ4TkxLVFZqZllnRkhlQkRk"
        + "Q2JyckVUZDR2Qk13RHRBbmpQcjNDVkN3d3gyYkFRVDZTbHhGSjNmajJoaHlJcHE3cGM4clppYjVqTnlYS3dmQnVrVFZZWm96a3NodCAtIExvaHlBU2FLcFlUcDhMdE5aIC0gdyAifSw"
        + "icHJvb2YiOiJqd3MifSwibmFtZSI6Ik15IEZpcnN0IENsaWVu"
        + "dCIsInVyaSI6Imh0dHA6XC9cL2xvY2FsaG9zdFwvY2xpZW50XC9jbGllbnRJRCJ9LCJpbnRlcmFjdCI6eyJzdGFydCI6WyJyZWRpcmVjdCJ"
        + "dLCJmaW5pc2giOnsibWV0aG9kIjoicmVkaXJlY3QiLCJub25jZSI6ImQ5MDIxMzg4NGI4NDA5MjA1MzhiNWM1MSIsInVyaSI6Imh0dHA6XC9cL2xvY2FsaG9zdFwvY2xpZW50"
        + "XC9yZXF1ZXN0LWRvbmUifX0sImFjY2Vzc190b2tlbiI6eyJhY2Nlc3MiOlt7ImFjdGlvbnMiOlsicmVhZCIsInByaW50Il0sImxvY2F0aW9ucyI6WyJodHRwOlwvXC9sb2Nhb"
        + "Ghvc3RcL3Bob3RvcyJdLCJkYXRhdHlwZXMiOlsibWV0YWRhdGEiLCJpbWFnZXMiXSwidHlwZSI6InBob3RvLWFwaSJ9XX0sInN1YmplY3QiOnsic3ViX2lkcyI6WyJpc3Nfc3"
        + "ViIiwiZW1haWwiXX19.LUyZ8_fERmxbYARq8kBYMwzcd8GnCAKAlo2ZSYLRRNAYWPrp2XGLJOvg97WK1idf_LB08OJmLVsCXxCvn9mgaAkYNL_ZjHcusBvY1mNo0E1sdTEr31"
        + "CVKfC-6WrZCscb8YqE4Ayhh0Te8kzSng3OkLdy7xN4xeKuHzpF7yGsM52JZ0cBcTo6WrYEfGdr08AWQJ59ht72n3jTsmYNy9A6I4Wrvfgj3TNxmwYojpBAi"
        + "cfjnzA1UVcNm9F_xiSz1_y2tdH7j5rVqBMQife-k9Ewk95vr3lurthenliYSNiUinVfoW1ybnaIBcTtP1_YCxg_h1y-B5uZEvYNGCuoCqa6IQ";

    String[] parts = exjws.split("\\.");
    String payload = new Base64URL(parts[1]).decodeToString();
    JsonObject jwk  = JsonParser.parseString(payload).getAsJsonObject().get("client")
            .getAsJsonObject().get("key").getAsJsonObject().get("jwk").getAsJsonObject();

    BigInteger modulus = new BigInteger(1, new Base64URL(jwk.get("n").getAsString()).decode());  
    BigInteger exponent = new BigInteger(1, new Base64URL(jwk.get("e").getAsString()).decode());
    byte[] signingInfo = String.join(".",parts[0],parts[1]).getBytes(StandardCharsets.UTF_8);
    byte[] b64DecodedSig = new Base64(parts[2]).decode();
    
    PublicKey pub = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
    
    Signature verifier = Signature.getInstance("SHA256withRSA");    
    verifier.initVerify(pub);
    verifier.update(signingInfo);
    boolean okay = verifier.verify(b64DecodedSig);
    System.out.println(okay);
}

Le résultat de verify() renvoie actuellement false.

J'ai essayé de générer des paires de clés RSA, de signer et de vérifier à l'aide des clés de génération et cela a fonctionné . Je soupçonne que mon problème est que la clé RSA construite dans le code ci-dessus est erronée. Toute aide appréciée.

MODIFIER

La bibliothèque JSON est Gson

JWK bibliothèque est nismus-jose-jwt qui fournit Base64 et Base64URl

0
Scott 26 févr. 2021 à 19:03

2 réponses

Meilleure réponse

De la discussion avec @Topaco dans les commentaires:

Le code de la question construit avec succès la clé publique RSA à partir du module n et de l'exposant e.

Cependant, l'appel Signature.verify() renvoie false car la clé publique spécifiée dans JWK dans la requête ne correspond pas à la clé utilisée pour signer la requête.

0
Scott 12 mars 2021 à 15:34

J'utilise une bibliothèque JWT pour cette tâche (je sais que c'est un peu exagéré, mais ça marche ...): https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/

Ils fournissent une interface facile à utiliser et vous trouverez ci-dessous un exemple de code qui génère une paire de clés RSA et imprime la clé publique, puis convertit cette clé publique au format JWK (à imprimer également) suivi de la conversion «finale» du format JWK au format RSAPublicKey de Java - la clé publique d'origine est identique à la nouvelle clé publique «double convertie»:

RSA converting between Java keys and JWK keys
rsaPublicKey:
Sun RSA public key, 2048 bits
  params: null
  modulus: 26357316308141920246706187189832816184464669247574329274151600014987833498613081305553907167489639882497901020042668019684731733203493602029515963993706600847721534104752032126130361576446376774646308346723928903197131878300000630951097323650413651136361398382777541880437222482333326912353931641531474275115618239345544686220478026629436520040030688170796270228708165193211856330191604982765859609032534442818720461696078063893165568447273933782242398761845509532495844704423556107073518195030616464416564865911759432179943444938978123330642161124144169230685337930276039065398676755273689018037129036026967769360801
  public exponent: 65537

jwkRsaPublicKey (JWK-Format)
{"kty":"RSA","e":"AQAB","n":"0MpIJE0koFXx5sZOOI-XsEMMQfvwHkizj1jaYGATZEz0YTdf-WUDrO2JeELP1UvwHRbD5Mt0y0IvSYEjG4btVoZWjoJwEIz-bT7rtJNnZ9bjY8vMYloCUM81nTLve0sVRqkjw3S7IFXsTXx05vkY7oV25Z9YeZH2f5b1ph3JGcTrQF8d3XZy6XAM_KaWWOPTwzoNtr3JQQzUJ2vS_BGCJyiVU1cEB0RlRu1Gd9EPqDcMGAN2nMoHUuQw0qNTd-ms0Du0RGnktRDpcm3SXLsUt2J4adbPp02eXjn-TDTISzR6FywC0sAL6ED0EqWhOgqEf7EftctSJGGdgLOkmL4poQ"}

rsaPublicKeyFromJwk:
Sun RSA public key, 2048 bits
  params: null
  modulus: 26357316308141920246706187189832816184464669247574329274151600014987833498613081305553907167489639882497901020042668019684731733203493602029515963993706600847721534104752032126130361576446376774646308346723928903197131878300000630951097323650413651136361398382777541880437222482333326912353931641531474275115618239345544686220478026629436520040030688170796270228708165193211856330191604982765859609032534442818720461696078063893165568447273933782242398761845509532495844704423556107073518195030616464416564865911759432179943444938978123330642161124144169230685337930276039065398676755273689018037129036026967769360801
  public exponent: 65537

Ce code n'a pas de traitement d'exception et est uniquement à des fins éducatives:

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.RSAKey;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey;

public class ConvertRsaKeysJavaJwk {
    public static void main(String[] args) throws NoSuchAlgorithmException, JOSEException {
        System.out.println("RSA converting between Java keys and JWK keys");
        // generate a RSA key pair
        KeyPair rsaKeyPair = generateRsaKeyPair(2048);
        RSAPublicKey rsaPublicKey = (RSAPublicKey) rsaKeyPair.getPublic();
        System.out.println("rsaPublicKey:\n" + rsaPublicKey);
        // import the ecdsaPublicKey to JWK
        // usage of nimbus-jose-jwt
        // https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/
        RSAKey jwkRsaPublicKey = new RSAKey.Builder(rsaPublicKey).build();
        System.out.println("\njwkRsaPublicKey (JWK-Format)\n" + jwkRsaPublicKey);
        // convert jwk to java
        RSAPublicKey rsaPublicKeyFromJwk = jwkRsaPublicKey.toRSAPublicKey();
        System.out.println("\nrsaPublicKeyFromJwk:\n" + rsaPublicKeyFromJwk);
    }

    public static KeyPair generateRsaKeyPair(int keylengthInt) throws NoSuchAlgorithmException {
        KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("RSA");
        keypairGenerator.initialize(keylengthInt, new SecureRandom());
        return keypairGenerator.generateKeyPair();
    }
}
-1
Michael Fehr 26 févr. 2021 à 17:03