2009-12-03 13 views
3

J'implémente une interface pour le service de paiement numérique appelée Suomen Verkkomaksut. Les informations sur le paiement leur sont envoyées via un formulaire HTML. Pour s'assurer que personne ne manipule les informations pendant le transfert, un hachage MD5 est calculé aux deux extrémités avec une clé spéciale qui ne leur est pas envoyée. Mon problème est que pour une raison quelconque, ils semblent décider que les données entrantes sont encodées avec ISO-8859-1 et non UTF-8. Le hachage que je leur ai envoyé est calculé avec des chaînes UTF-8 donc il diffère du hash qu'ils calculent.MD5 Hash de la chaîne ISO-8859-1 en Java

J'ai essayé avec le code suivant:

String prehash = "6pKF4jkv97zmqBJ3ZL8gUw5DfT2NMQ|13466|123456||Testitilaus|EUR|http://www.esimerkki.fi/success|http://www.esimerkki.fi/cancel|http://www.esimerkki.fi/notify|5.1|fi_FI|0412345678|0412345678|[email protected]|Matti|Meikäläinen||Testikatu 1|40500|Jyväskylä|FI|1|2|Tuote #101|101|1|10.00|22.00|0|1|Tuote #202|202|2|8.50|22.00|0|1"; 
String prehashIso = new String(prehash.getBytes("ISO-8859-1"), "ISO-8859-1"); 

String hash = Crypt.md5sum(prehash).toUpperCase(); 
String hashIso = Crypt.md5sum(prehashIso).toUpperCase(); 

Malheureusement les deux hash sont identiques à la valeur C83CF67455AF10913D54252737F30E21. La valeur correcte pour cet exemple est 975816A41B9EB79B18B3B4526569640E selon la documentation de Suomen Verkkomaksut.

Existe-t-il un moyen de calculer le hachage MD5 en Java avec les chaînes ISO-8859-1?

MISE À JOUR: En attendant la réponse de Suomen Verkkomaksut, j'ai trouvé une autre façon de faire le hachage. Michael Borgwardt a corrigé ma compréhension de la chaîne et des encodages et j'ai cherché un moyen de faire du hash []. Apache Commons est une excellente source de bibliothèques et j'ai trouvé leur classe DigestUtils qui a une fonction md5hex qui prend l'entrée byte [] et renvoie une chaîne hexadécimale de 32 caractères.

Pour une raison quelconque, cela ne fonctionne toujours pas. Ces deux renvoient la même valeur:

DigestUtils.md5Hex(prehash.getBytes()); 
DigestUtils.md5Hex(prehash.getBytes("ISO-8859-1")); 
+0

N'utilisez jamais la première forme de 'getBytes()' si vous voulez obtenir un résultat prévisible. Il utilise l'encodage par défaut de votre système. Vous venez de Finlande, il est fort probable que votre encodage par défaut soit 'ISO-8859-1', donc les deux appels produiront les mêmes résultats. –

Répondre

2

Java a une classe standard java.security.MessageDigest, pour calculer différents hashes.

Voici l'exemple de code

include java.security.MessageDigest; 

// Exception handling not shown 

String prehash = ... 

final byte[] prehashBytes= prehash.getBytes("iso-8859-1"); 

System.out.println(prehash.length()); 
System.out.println(prehashBytes.length); 

final MessageDigest digester = MessageDigest.getInstance("MD5"); 

digester.update(prehashBytes); 

final byte[] digest = digester.digest(); 

final StringBuffer hexString = new StringBuffer(); 

for (final byte b : digest) { 
    final int intByte = 0xFF & b; 

    if (intByte < 10) 
    { 
     hexString.append("0"); 
    } 

    hexString.append(
     Integer.toHexString(intByte) 
    ); 
} 

System.out.println(hexString.toString().toUpperCase()); 

Malheureusement pour vous, il produit le même hachage "C83CF67455AF10913D54252737F30E21". Donc, je suppose que votre classe Crypto est exonérée. J'ai spécifiquement ajouté les impressions de longueur prehash et prehashBytes pour vérifier qu'effectivement 'ISO-8859-1' est utilisé. Dans ce cas les deux sont 328.

Quand j'ai fait presash.getBytes("utf-8") il a produit "9CC2E0D1D41E67BE9C2AB4AABDB6FD3" (et la longueur du tableau d'octets est devenu 332). Encore une fois, pas le résultat que vous recherchez. Donc, je suppose que Suomen Verkkomaksut fait un massage de la chaîne prehash qu'ils n'ont pas documenté, ou que vous avez oublié.

+0

Votre fonction de hachage ne remplit pas le zéro si l'octet est inférieur à 10. – BalusC

+0

Eh bien, peut-être que je vais devoir attendre une réponse de leur part. Merci pour l'exemple de code fourni. –

+0

@BalusC. Vous avez parfaitement raison. J'ai corrigé mon exemple. Toujours me bat pourquoi Java n'a pas Byte.toHexString et Byte.toUpperHexString qui fait la bonne chose. –

1

Si vous envoyez UTF-8 données codées qu'ils traitent comme ISO-8859-1 alors qui pourrait être la source de votre problème. Je vous suggère soit d'envoyer les données dans ISO-8859-1 ou d'essayer de communiquer à Suomen Verkkomaksut que vous envoyez UTF-8. Dans un protocole basé sur http, vous le faites en ajoutant charset = utf-8 à Content-Type dans l'en-tête HTTP.

Une façon d'exclure certains problèmes consiste à essayer une chaîne prehash qui contient uniquement des caractères codés de la même manière en UTF-8 et ISO-8859-1. D'après ce que je peux voir, vous pouvez y parvenir en supprimant tous les caractères «ä» de la chaîne que vous avez utilisée.

+0

J'ai déjà et On la page. Malheureusement, cela ne semble pas aider. Mais vous avez raison, peut-être que je devrais juste les contacter. –

8

Vous semblez mal comprendre le fonctionnement du codage de chaîne, et votre API de classe Crypt est suspecte.

Les chaînes n'ont pas vraiment "d'encodage" - un encodage est ce que vous utilisez pour convertir entre chaînes et octets.

Les chaînes Java sont stockées en interne sous la forme UTF-16, mais cela n'a pas vraiment d'importance, car MD5 fonctionne sur des octets, pas sur des chaînes. Votre méthode Crypt.md5sum() doit convertir les chaînes qui lui ont été transmises en premier - quel encodage utilise-t-il pour cela? C'est probablement la source de votre problème.

Votre code exemple est assez absurde que le seul effet de cette ligne a:

String prehashIso = new String(prehash.getBytes("ISO-8859-1"), "ISO-8859-1"); 

est de remplacer les caractères qui ne peuvent pas être représentés dans la norme ISO-8859-1 avec des points d'interrogation.

+0

Merci pour la clarification. –

+0

+1 sur la suspecte de la classe 'Crypt'. Cela suggère également qu'il peut y avoir une confusion entre le cryptage et le hachage cryptographique (mais il peut aussi y en avoir pas un, selon le reste de la classe). – Romain

2

Je ne sais pas si vous avez résolu votre problème, mais j'ai eu un problème similaire avec les chaînes codées ISO-8859-1 avec des caractères nordiques ä & ö et calculant un hachage SHA-256 pour comparer avec des choses dans la documentation. L'extrait suivant a fonctionné pour moi:

import java.security.MessageDigest; 
//imports omitted 

@Test 
public void test() throws ProcessingException{ 
String test = "iamastringwithäöchars";   
System.out.println(this.digest(test));  
} 

public String digest(String data) throws ProcessingException { 
    MessageDigest hash = null; 

    try{ 
     hash = MessageDigest.getInstance("SHA-256"); 
    } 
    catch(Throwable throwable){ 
     throw new ProcessingException(throwable); 
    } 
    byte[] digested = null; 
    try { 
     digested = hash.digest(data.getBytes("ISO-8859-1")); 
    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } 

    String ret = BinaryUtils.BinToHexString(digested); 
    return ret; 
} 

Transformer octets à chaîne hexadécimale il y a beaucoup d'options, y compris les communes apache classe codec Hex mentionné dans ce fil.