71 votes

Utilisation de SHA1 et RSA avec java.security.Signature vs MessageDigest et Cipher

J'essaie de comprendre ce que le Java java.de sécurité.La Signature de la classe. Si je calcule une SHA1 résumé de message, puis crypter, qui digèrent à l'aide de RSA, j'obtiens un résultat différent à demander à la Signature de la classe à signer la même chose:

// Generate new key
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
String plaintext = "This is the message being signed";

// Compute signature
Signature instance = Signature.getInstance("SHA1withRSA");
instance.initSign(privateKey);
instance.update((plaintext).getBytes());
byte[] signature = instance.sign();

// Compute digest
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
byte[] digest = sha1.digest((plaintext).getBytes());

// Encrypt digest
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] cipherText = cipher.doFinal(digest);

// Display results
System.out.println("Input data: " + plaintext);
System.out.println("Digest: " + bytes2String(digest));
System.out.println("Cipher text: " + bytes2String(cipherText));
System.out.println("Signature: " + bytes2String(signature));

Résultats dans (par exemple):

Données d'entrée: C'est le message en cours de signature
Digest: 62b0a9ef15461c82766fb5bdaae9edbe4ac2e067
Le texte chiffré: 057dc0d2f7f54acc95d3cf5cba9f944619394711003bdd12...
Signature: 7177c74bbbb871cc0af92e30d2808ebae146f25d3fd8ba1622...

Je dois avoir une incompréhension fondamentale de ce que la Signature est en train de faire - j'ai tracé à travers elle, et elle semble être l'appel de mise à jour sur un MessageDigest objet, avec l'algorithme défini à SHA1 comme je l'espère, par l'obtention de l'empreinte, puis de faire le cryptage. Ce qui rend les résultats diffèrent-ils?

EDIT:

Leonidas m'a fait vérifier si la signature régime est censé faire ce que je pense. Il existe deux types de signature définie dans la RFC:

La première de ces (PKCS1) est celui que j'ai décrit ci-dessus. Il utilise une fonction de hachage à créer un digest, et crypte le résultat avec une clé privée.

Le deuxième algorithme utilise un hasard sel de la valeur, et est plus sûre, mais non-déterministe. La signature produite à partir du code ci-dessus ne change pas si la même clé est utilisée à plusieurs reprises, donc je ne pense pas qu'il se PSS.

EDIT:

Voici l' bytes2string méthode que j'utilisais:

private static String bytes2String(byte[] bytes) {
    StringBuilder string = new StringBuilder();
    for (byte b : bytes) {
        String hexString = Integer.toHexString(0x00FF & b);
        string.append(hexString.length() == 1 ? "0" + hexString : hexString);
    }
    return string.toString();
}

54voto

Mike Houston Points 4320

OK, j'ai travaillé sur ce qui se passe. J'étais stupide. Leonidas a raison, il n'y a pas que le hachage chiffré, c'est l'identifiant de l'algorithme de hachage concaténé avec le résumé:

   DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }
 

C'est pourquoi ils sont différents.

12voto

Romulo Pereira Points 21

Pour produire les mêmes résultats:

 MessageDigest sha1 = MessageDigest.getInstance("SHA1", BOUNCY_CASTLE_PROVIDER);
byte[] digest = sha1.digest(conteudo);
DERObjectIdentifier sha1oid_ = new DERObjectIdentifier("1.3.14.3.2.26");

AlgorithmIdentifier sha1aid_ = new AlgorithmIdentifier(sha1oid_, null);
DigestInfo di = new DigestInfo(sha1aid_, digest);

byte[] plainSig = di.getDEREncoded();
Cipher cipher = Cipher.getInstance("RSA", BOUNCY_CASTLE_PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, chavePrivada);
byte[] assinatura = cipher.doFinal(plainSig);
 

5voto

magiconair Points 1197

Une version légèrement plus efficace de la méthode bytes2String est

 private static final char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static String byteArray2Hex(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * 2);
    for (final byte b : bytes) {
        sb.append(hex[(b & 0xF0) >> 4]);
        sb.append(hex[b & 0x0F]);
    }
    return sb.toString();
}
 

4voto

Leonidas Points 2059

Euh, après avoir compris votre question: êtes-vous sûr que la méthode signature ne crée qu'un SHA1 et le chiffre? GPG et autres proposent de compresser / effacer le signe des données. Peut-être que java-signature-alg crée également une signature détachable / attachable.

0voto

J'ai un problème similaire, j'ai testé l'ajout de code et trouvé des résultats intéressants. Avec ce code que j'ai ajouter, je peux en déduire que, selon le "fournisseur" à utiliser, l'entreprise peut être différent? (parce que les données incluses dans le chiffrement n'est pas toujours égal à tous les fournisseurs).

Les résultats de mon test.

Conclusion.- Signature À Déchiffrer= ???(corbeille) + DigestInfo (si nous connaissons la valeur de "trash", les signatures numériques sont égaux)

IDE Eclipse de SORTIE...

Données d'entrée: C'est le message en cours de signature

Digest: 62b0a9ef15461c82766fb5bdaae9edbe4ac2e067

DigestInfo: 3021300906052b0e03021a0500041462b0a9ef15461c82766fb5bdaae9edbe4ac2e067

Signature à Déchiffrer: 1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a0500041462b0a9ef15461c82766fb5bdaae9edbe4ac2e067

CODE

import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.asn1.x509.DigestInfo;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
public class prueba {
/**
* @param args
* @throws NoSuchProviderException 
* @throws NoSuchAlgorithmException 
* @throws InvalidKeyException 
* @throws SignatureException 
* @throws NoSuchPaddingException 
* @throws BadPaddingException 
* @throws IllegalBlockSizeException 
*///
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// TODO Auto-generated method stub
KeyPair keyPair = KeyPairGenerator.getInstance("RSA","BC").generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey puKey = keyPair.getPublic();
String plaintext = "This is the message being signed";
// Hacer la firma
Signature instance = Signature.getInstance("SHA1withRSA","BC");
instance.initSign(privateKey);
instance.update((plaintext).getBytes());
byte[] signature = instance.sign();
// En dos partes primero hago un Hash
MessageDigest digest = MessageDigest.getInstance("SHA1", "BC");
byte[] hash = digest.digest((plaintext).getBytes());
// El digest es identico a  openssl dgst -sha1 texto.txt
//MessageDigest sha1 = MessageDigest.getInstance("SHA1","BC");
//byte[] digest = sha1.digest((plaintext).getBytes());
AlgorithmIdentifier digestAlgorithm = new AlgorithmIdentifier(new
DERObjectIdentifier("1.3.14.3.2.26"), null);
// create the digest info
DigestInfo di = new DigestInfo(digestAlgorithm, hash);
byte[] digestInfo = di.getDEREncoded();
//Luego cifro el hash
Cipher cipher = Cipher.getInstance("RSA","BC");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] cipherText = cipher.doFinal(digestInfo);
//byte[] cipherText = cipher.doFinal(digest2);
Cipher cipher2 = Cipher.getInstance("RSA","BC");
cipher2.init(Cipher.DECRYPT_MODE, puKey);
byte[] cipherText2 = cipher2.doFinal(signature);
System.out.println("Input data: " + plaintext);
System.out.println("Digest: " + bytes2String(hash));
System.out.println("Signature: " + bytes2String(signature));
System.out.println("Signature2: " + bytes2String(cipherText));
System.out.println("DigestInfo: " + bytes2String(digestInfo));
System.out.println("Signature Decipher: " + bytes2String(cipherText2));
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X