web-dev-qa-db-fra.com

Pourquoi les signatures RSA-SHA256 que je génère avec OpenSSL et Java différentes?

Je souhaite générer une signature RSA-SHA256 en Java, mais je ne parviens pas à obtenir la même signature qu'avec OpenSSL sur la console.

C'est ce que j'ai fait avec OpenSSL (suivant ce tutoriel ):

Générer une paire de clés:

openssl genrsa -out private.pem 1024

Extraire la clé publique:

openssl rsa -in private.pem -out public.pem -outform PEM -pubout

Créez un hachage de données:

echo 'data to sign' > data.txt
openssl dgst -sha256 < data.txt > hash

Le fichier de hachage généré commence par (stdin)= ce que j'ai enlevé à la main (d'abord oublié de le mentionner, merci mata).

Hachage de signe:

openssl rsautl -sign -inkey private.pem -keyform PEM -in hash  > signature

Pour reproduire les résultats en Java j'ai d'abord converti la clé privée de PEM en DER:

openssl pkcs8 -topk8 -inform PEM -outform DER -in private.pem -nocrypt > private.der

Maintenant, j'ai écrit cette classe Java pour générer la même signature:

public class RSATest {

    public static void main(String[] args) throws IOException,
            NoSuchAlgorithmException, InvalidKeySpecException,
            InvalidKeyException, SignatureException {

        byte[] encodedPrivateKey = readFile("private.der");
        byte[] content = readFile("data.txt");

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory
                .generatePrivate(keySpec);

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(content);
        byte[] signatureBytes = signature.sign();

        FileOutputStream fos = new FileOutputStream("signature-Java");
        fos.write(signatureBytes);
        fos.close();
    }

    private static byte[] readFile(String filename) throws IOException {
        File file = new File(filename);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                file));
        byte[] bytes = new byte[(int) file.length()];
        bis.read(bytes);
        bis.close();
        return bytes;
    }

}

Malheureusement, les résultats ne sont pas les mêmes, donc je pense que j'ai dû faire quelque chose de mal, mais je ne sais pas quoi. Quelqu'un parmi vous peut-il m'aider à trouver le bug?

25
Arthur Dent
openssl dgst -sha256 < data.txt

produit quelque chose comme:

 (stdin) = b39eaeb437e33087132f01c2abc60c6a16904ee3771cd7b0d622d01061b40729 

remarquez le (stdin)= '? vous ne voulez pas que cela fasse partie de votre hachage, si vous devez créer un résumé, utilisez le -binary option.

essayez de l'utiliser pour signer vos données:

openssl sha -sha256 -sign private.pem < data.txt

Cela fait tout ce dont vous avez besoin.


modifier - un peu plus d'explications:

créons un résumé et montrons-le

$ openssl dgst -sha256 -binary < data.txt > digest
$ hd digest
00000000  26 3b 0a a1 2e b9 32 db  b8 dc d3 6f 37 94 0b 05  |&;....2....o7...|
00000010  71 9c ba 79 46 34 28 9f  5c 5b 98 9a 64 61 c9 ec  |q..yF4(.\[..da..|

maintenant, nous prenons ce résumé et nous nous connectons avec rsautl:

$ openssl rsautl -sign -inkey private.pem < digest > sign1
$ hd sign1
00000000  1b 7a cf a4 8d 41 8e 04  ed 3a bb ba 86 f1 f8 e0  |.z...A...:......|
00000010  df f7 47 3e d7 a7 f4 90  7a 05 f8 7f 45 e5 29 e7  |..G>....z...E.).|
00000020  9f f4 2c 91 97 2f e7 26  69 9f 6a 07 a3 48 1b 85  |..,../.&i.j..H..|
00000030  2e f8 ee 44 4d 25 9f ae  05 95 81 c9 e3 07 68 ad  |...DM%........h.|

signons maintenant le même fichier en utilisant dgst directement:

$ openssl dgst -sha256 -sign private.pem < data.txt > sign2
$ hd sign2
00000000  15 c2 94 87 eb e6 cb 45  c8 63 0c 97 60 d3 07 f3  |.......E.c..`...|
00000010  dc 65 32 ad 44 1c c2 2a  7f a3 e1 fc dd 84 27 8c  |.e2.D..*......'.|
00000020  77 a6 97 2b 33 6b c6 d7  7d e1 1d 39 5c 48 b6 48  |w..+3k..}..9\H.H|
00000030  cb 18 be bf 6a 66 90 d3  88 89 52 6c dd d1 b9 99  |....jf....Rl....|

Alors qu'est-ce qui est différent ici? Pour voir cela, nous pouvons vérifier la signature et afficher la sortie brute. Les deux fichiers contiennent le résumé, mais les métadonnées et le remplissage sont différents:

$ openssl rsautl -raw -verify -inkey private.pem < sign1 | hd
00000000  00 01 ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff 00  |................|
00000020  26 3b 0a a1 2e b9 32 db  b8 dc d3 6f 37 94 0b 05  |&;....2....o7...|
00000030  71 9c ba 79 46 34 28 9f  5c 5b 98 9a 64 61 c9 ec  |q..yF4(.\[..da..|

$ openssl rsautl -raw -verify -inkey private.pem < sign2 | hd
00000000  00 01 ff ff ff ff ff ff  ff ff ff ff 00 30 31 30  |.............010|
00000010  0d 06 09 60 86 48 01 65  03 04 02 01 05 00 04 20  |...`.H.e....... |
00000020  26 3b 0a a1 2e b9 32 db  b8 dc d3 6f 37 94 0b 05  |&;....2....o7...|
00000030  71 9c ba 79 46 34 28 9f  5c 5b 98 9a 64 61 c9 ec  |q..yF4(.\[..da..|

Pour voir cela plus clairement, nous pouvons essayer d'utiliser le -asn1parse flag, qui ne fonctionnera pas pour la première signature, mais pour la seconde il montre la structure correcte de la signature:

$ openssl rsautl -verify -inkey private.pem -asn1parse < sign1
Error in encoding
139931349546656:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:asn1_lib.c:142:

$ openssl rsautl -verify -inkey private.pem -asn1parse < sign2
    0:d=0  hl=2 l=  49 cons: SEQUENCE          
    2:d=1  hl=2 l=  13 cons:  SEQUENCE          
    4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
   15:d=2  hl=2 l=   0 prim:   NULL              
   17:d=1  hl=2 l=  32 prim:  OCTET STRING      
      0000 - 26 3b 0a a1 2e b9 32 db-b8 dc d3 6f 37 94 0b 05   &;....2....o7...
      0010 - 71 9c ba 79 46 34 28 9f-5c 5b 98 9a 64 61 c9 ec   q..yF4(.\[..da..
44
mata