[英]Hashlib md5 in python returning incorrect digests for some unicode characters?
我一直在研究python和Java的MD5實現,並遇到了使我感到困惑的怪癖。
以下python腳本說明了該問題:
# -*- coding: utf-8 -*-
import hashlib
def md5hash(x):
m = hashlib.md5()
m.update(x)
return m.hexdigest()
print md5hash('\xdb')
print md5hash('Û')
輸出:
98fd00d788afe2a5fa5e4f8e1666638b
31ecfb09f120720a55d96a2034f5d00b
考慮到Û
應該等效於\\xdb
,我希望這兩個摘要等效。 我用Java構建了等效的實現,以獲得更多的見解:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Test {
public static void main(String[] args) throws Exception {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update("\u00db".getBytes());
System.out.println(bytesToHex(m.digest()));
m.update("Û".getBytes());
System.out.println(bytesToHex(m.digest()));
}
final protected static char[] hexArray = "0123456789abcdef".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
輸出:
31ecfb09f120720a55d96a2034f5d00b
31ecfb09f120720a55d96a2034f5d00b
正如預期的那樣,Java的輸出是一致的。 這使我相信md5hash('\\xdb')
輸出的結果不正確,但是我不確定丟失了什么。 有什么想法嗎?
您的假設是不正確的。 您使用以下代碼啟動了Python源代碼:
# -*- coding: utf-8 -*-
Û
不等同於\\xdb
在這種情況下; 而是兩個字節:
>>> u'Û'.encode('utf8')
'\xc3\x9b'
Python在這里是完全一致的:
>>> import hashlib
>>> hashlib.md5('\xc3\x9b').hexdigest()
'31ecfb09f120720a55d96a2034f5d00b'
>>> hashlib.md5('\xdb').hexdigest()
'98fd00d788afe2a5fa5e4f8e1666638b'
在Java中,您改用Unicode代碼點開始,將其轉換為UTF-8字節:
"\u00db".getBytes()
Python的等價是使用一個unicode
字符串文字,無論是\\uhhhh
或\\xhh
轉義序列:
>>> u'\u00db'.encode('utf8')
'\xc3\x9b'
>>> u'\xdb'.encode('utf8')
'\xc3\x9b'
注意u
前綴以生成unicode
字符串。 不帶u
前綴的\\xdb
是一個字節字符串 ,而不是Unicode代碼點,只有將其解碼為Latin 1時 ,您才會獲得相同的Unicode字符串:
>>> '\xdb'.decode('latin1')
u'\xdb'
>>> '\xdb'.decode('latin1').encode('utf8')
'\xc3\x9b'
您可能想學習Python和Unicode。 看到:
Ned Batchelder的實用Unicode
為了完整起見:
考慮到
Û
應該等效於\\xdb
,我希望這兩個摘要等效。
Û是您似乎正在使用的UTF-8中的C3 9B
(它是您聲明的編碼)。 DB
將為ISO-8859-1。
>>> import hashlib
>>> hashlib.md5(b'\xc3\x9b').hexdigest()
'31ecfb09f120720a55d96a2034f5d00b'
-
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.