web-dev-qa-db-fra.com

Création d'une clé publique RSA à partir d'une chaîne

J'ai généré cette clé publique de test à l'aide de 1024 RSA, puis je l'ai encodée en DER et Base64 dans une autre plate-forme de codage. J'ai copié la clé dans une chaîne sous Android/Eclipse et j'essaie de la transformer en clé publique à l'aide de KeyFactory. Il me donne juste une exception InvalidKeySpecException, peu importe ce que j'essaie. Tout conseil serait apprécié.

     private void prepKeys() {
         String AppKeyPub = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5" +
"5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ" +
"OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";

        // create the key factory          
            try {
                KeyFactory kFactory = KeyFactory.getInstance("RSA");  
                // decode base64 of your key
                byte yourKey[] =  Base64.decode(AppKeyPub,0);
                // generate the public key
                X509EncodedKeySpec spec =  new X509EncodedKeySpec(yourKey);
                PublicKey publicKey = (PublicKey) kFactory.generatePublic(spec);

            System.out.println("Public Key: " + publicKey);  

            } catch (Exception e) {
                // TODO Auto-generated catch block  
                e.printStackTrace(); 
            }

         }
15
raximus

La clé que vous avez est au format PKCS # 1 au lieu de la structure SubjectPublicKeyInfo qui Java accepte. PKCS # 1 est le codage des paramètres RSA uniquement et il manque des éléments tels qu'un identifiant d'algorithme. SubjectPublicKeyInfo utilise PKCS # 1 en interne - pour les clés publiques RSA de toute façon.

La clé publique PKCS # 1 étant à la fin de la structure SubjectPublicKeyInfo, il est possible de simplement préfixer les octets afin qu'ils deviennent un RSA SubjectPublicKeyInfo. Cette solution est plus facile à réaliser sans bibliothèques supplémentaires telles que Bouncy Castle. Donc, si vous devez vous passer d'une bibliothèque externe, vous pouvez consulter ma réponse ici .


Alternativement, un simple décodeur BER pourrait être écrit pour décoder la structure en deux valeurs BigInteger. La structure elle-même ce n'est pas si compliqué mais le codage de longueur BER/DER prend un certain temps pour s'y habituer.

Cependant, vous pouvez également utiliser Bouncy Castle (API légère) pour résoudre vos problèmes:

String publicKeyB64 = "MIGHAoGBAOX+TFdFVIKYyCVxWlnbGYbmgkkmHmEv2qStZzAFt6NVqKPLK989Ow0RcqcDTZaZBfO5"
        + "5JSVHNIKoqULELruACfqtGoATfgwBp4Owfww8M891gKNSlI/M0yzDQHns5CKwPE01jD6qGZ8/2IZ"
        + "OjLJNH6qC9At8iMCbPe9GeXIPFWRAgER";
// ok, you may need to use the Base64 decoder of bouncy or Android instead
byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey generatedPublic = kf.generatePublic(keySpec);
System.out.printf("Modulus: %X%n", modulus);
System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent); // 17? OK.
System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);

Comme vous pouvez le voir, il ne nécessite en fait qu'une seule classe en tant qu'interface, bien que cela soit bien sûr sauvegardé avec l'ensemble des fonctionnalités du décodeur ASN.1/BER dans Bouncy Castle.


Notez qu'il peut être nécessaire de changer le décodeur Base 64 en le Android spécifique) (Android.util.Base64) . Ce code a été testé sur un équivalent Java runtime.

11
Maarten Bodewes