带 ASCII 字符的 MD5
我有一个字符串
wDevCopyright = [NSString stringWithFormat:@"Copyright: %c 1995 by WIRELESS.dev, Corp Communications Inc., All rights reserved.",0xa9];
,并且要调用它,
-(NSString *)getMD5:(NSString *)source
{
const char *src = [source UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(src, strlen(src), result);
return [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
]; //ret;
}
因为 0xa9 *src = [source UTF8String] 不会创建表示该字符串的字符,因此返回一个与其他平台无法比较的 munge。
我尝试使用 NSASCIIStringEncoding 对字符进行编码,但它破坏了代码。
如何使用包含 ASCII 字符的字符串调用 CC_MD5 并获得与 Java 中相同的哈希值?
更新代码请求:
Java
private static char[] kTestASCII = {
169
};
System.out.println("\n\n>>>>> msg## " + (char)0xa9 + " " + (char)169 + "\n md5 " + md5(new String(kTestASCII), false) //unicode = false
结果>>>>味精## \251 \251 md5 a252c2c85a9e7756d5ba5da9949d57ed
ObjC
char kTestASCII [] = {
169
};
NSString *testString = [NSString stringWithCString:kTestASCII encoding:NSUTF8StringEncoding];
NSLog(@">>>> objC msg## int %d char %c md5: %@", 0xa9, 169, [self getMD5:testString]);
结果 >>>>> objC msg## int 169 char © md5: 9b759040321a408a5c7768b4511287a6
** 如前所述 - 没有 0xa9,Java 和 ObjC 中的哈希值是相同的。 中获得相同的 0xa9 哈希值,
我试图在 Java 和 ObjC Java MD5 代码
private static char[] kTestASCII = {
169
};
md5(new String(kTestASCII), false);
/**
* Compute the MD5 hash for the given String.
* @param s the string to add to the digest
* @param unicode true if the string is unciode, false for ascii strings
*/
public synchronized final String md5(String value, boolean unicode)
{
MD5();
MD5.update(value, unicode);
return WUtilities.toHex(MD5.finish());
}
public synchronized void update(String s, boolean unicode)
{
if (unicode)
{
char[] c = new char[s.length()];
s.getChars(0, c.length, c, 0);
update(c);
}
else
{
byte[] b = new byte[s.length()];
s.getBytes(0, b.length, b, 0);
update(b);
}
}
public synchronized void update(byte[] b)
{
update(b, 0, b.length);
}
//--------------------------------------------------------------------------------
/**
* Add a byte sub-array to the digest.
*/
public synchronized void update(byte[] b, int offset, int length)
{
for (int n = offset; n < offset + length; n++)
update(b[n]);
}
/**
* Add a byte to the digest.
*/
public synchronized void update(byte b)
{
int index = (int)((count >>> 3) & 0x03f);
count += 8;
buffer[index] = b;
if (index >= 63)
transform();
}
我相信我的问题是使用 NSData withEncoding 而不是 C char[] 或 Java byte[]。那么将我自己的字节滚动到 objC 中的 byte[] 中的最佳方法是什么?
I have a string
wDevCopyright = [NSString stringWithFormat:@"Copyright: %c 1995 by WIRELESS.dev, Corp Communications Inc., All rights reserved.",0xa9];
and to munge it I call
-(NSString *)getMD5:(NSString *)source
{
const char *src = [source UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(src, strlen(src), result);
return [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
]; //ret;
}
because of 0xa9 *src = [source UTF8String] does not create a char that represents the string, thus returning a munge that is not comparable with other platforms.
I tried to encode the char with NSASCIIStringEncoding but it broke the code.
How do I call CC_MD5 with a string that has ASCII characters and get the same hash as in Java?
Update to code request:
Java
private static char[] kTestASCII = {
169
};
System.out.println("\n\n>>>>> msg## " + (char)0xa9 + " " + (char)169 + "\n md5 " + md5(new String(kTestASCII), false) //unicode = false
Result >>>>> msg## \251 \251
md5 a252c2c85a9e7756d5ba5da9949d57ed
ObjC
char kTestASCII [] = {
169
};
NSString *testString = [NSString stringWithCString:kTestASCII encoding:NSUTF8StringEncoding];
NSLog(@">>>> objC msg## int %d char %c md5: %@", 0xa9, 169, [self getMD5:testString]);
Result >>>> objC msg## int 169 char © md5: 9b759040321a408a5c7768b4511287a6
** As stated earlier - without the 0xa9 the hashes in Java and ObjC are the same. I am trying to get the hash for 0xa9 the same in Java and ObjC
Java MD5 code
private static char[] kTestASCII = {
169
};
md5(new String(kTestASCII), false);
/**
* Compute the MD5 hash for the given String.
* @param s the string to add to the digest
* @param unicode true if the string is unciode, false for ascii strings
*/
public synchronized final String md5(String value, boolean unicode)
{
MD5();
MD5.update(value, unicode);
return WUtilities.toHex(MD5.finish());
}
public synchronized void update(String s, boolean unicode)
{
if (unicode)
{
char[] c = new char[s.length()];
s.getChars(0, c.length, c, 0);
update(c);
}
else
{
byte[] b = new byte[s.length()];
s.getBytes(0, b.length, b, 0);
update(b);
}
}
public synchronized void update(byte[] b)
{
update(b, 0, b.length);
}
//--------------------------------------------------------------------------------
/**
* Add a byte sub-array to the digest.
*/
public synchronized void update(byte[] b, int offset, int length)
{
for (int n = offset; n < offset + length; n++)
update(b[n]);
}
/**
* Add a byte to the digest.
*/
public synchronized void update(byte b)
{
int index = (int)((count >>> 3) & 0x03f);
count += 8;
buffer[index] = b;
if (index >= 63)
transform();
}
I believe that my issue is with using NSData withEncoding as opposed to a C char[] or the Java byte[]. So what is the best way to roll my own bytes into a byte[] in objC?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您遇到问题的字符 © 是 Unicode 版权符号 (00A9)。该字符的正确 UTF-8 编码是字节序列
0xc9 0xa9
。但是,您正在尝试从单字节序列
0xa9
进行转换,这不是任何字符的有效 UTF-8 编码。请参阅 http://www.unicode.org/versions 的表 3-7 /Unicode5.2.0/ch03.pdf#G7404 。由于这不是有效的 UTF-8 字节序列,stringWithCString
会将您的输入转换为 Unicode REPLACMENT_CHARACTER (FFFD)。当这个字符被编码回 UTF-8 时,它会产生字节序列0xef 0xbf 0xbd
。正如您的 Objective-C 示例所报告的,该序列的 MD5 是 9b759040321a408a5c7768b4511287a6。您的 Java 示例生成的 MD5 为 a252c2c85a9e7756d5ba5da9949d57ed,简单的实验表明它是字节序列
0xa9
的 MD5,我已经注意到它不是所需字符的有效 UTF-8 表示形式。我认为我们需要查看您正在使用的 Java md5() 方法的实现。我怀疑它只是删除每个 Unicode 字符的高字节以转换为字节序列以传递给 MessageDigest 类。这与您使用 UTF-8 编码的 Objective-C 实现不匹配。
注意:即使您修复了 Objective-C 实现以匹配 Java md5() 方法的编码,您的测试也需要进行一些调整,因为您不能将
stringWithCString
与NSUTF8StringEncoding
一起使用> 编码将字节序列0xa9
转换为NSString。更新
现在已经看到了使用已弃用的 getBytes 方法,我的建议是更改 Java 实现,如果可能的话,使用正确的方法UTF-8 编码。
然而,我怀疑您的要求是与当前的 Java 实现相匹配,即使它是错误的。因此,我建议您通过使用
NSString getCharacters:range:
来检索unichar
数组,然后手动创建一个数组,从而复制 Java 已弃用的 getBytes() 方法的不良行为通过获取每个 unichar 的低字节来计算字节数。The character you are having problems with, ©, is the Unicode COPYRIGHT SIGN (00A9). The correct UTF-8 encoding of this character is the byte sequence
0xc9 0xa9
.You are attempting, however to convert from the single-byte sequence
0xa9
which is not a valid UTF-8 encoding of any character. See table 3-7 of http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G7404 . Since this is not a valid UTF-8 byte sequence,stringWithCString
is converting your input to the Unicode REPLACEMENT_CHARACTER (FFFD). When this character is then encoded back into UTF-8, it yields the byte sequence0xef 0xbf 0xbd
. The MD5 of this sequence is 9b759040321a408a5c7768b4511287a6 as reported by your Objective-C example.Your Java example yields an MD5 of a252c2c85a9e7756d5ba5da9949d57ed, which simple experimentation shows is the MD5 of the byte sequence
0xa9
, which I have already noted is not a valid UTF-8 representation of the desired character.I think we need to see the implementation of the Java md5() method you are using. I suspect it is simply dropping the high bytes of every Unicode character to convert to a byte sequence for passing to the MessageDigest class. This does not match your Objective-C implementation where you are using a UTF-8 encoding.
Note: even if you fix your Objective-C implementation to match the encoding of your Java md5() method, your test will need some adjustment because you cannot use
stringWithCString
with theNSUTF8StringEncoding
encoding to convert the byte sequence0xa9
to an NSString.UPDATE
Having now seen the Java implementation using the deprecated getBytes method, my recommendation is to change the Java implementation, if at all possible, to use a proper UTF-8 encoding.
I suspect, however, that your requirements are to match the current Java implementation, even if it is wrong. Therefore, I suggest you duplicate the bad behavior of Java's deprecated getBytes() method by using
NSString getCharacters:range:
to retrieve an array ofunichar
s, then manually create an array of bytes by taking the low byte of each unichar.stringWithCString
需要一个以 null 结尾的 C 字符串。我认为kTestASCII[]
在 Objective-C 代码中不一定以 null 结尾。也许这就是差异的原因。尝试:
stringWithCString
requires a null terminated C-String. I don't think thatkTestASCII[]
is necessarily null terminated in your Objective-C code. Perhaps that is the cause of the difference.Try:
感谢 GBegan 的解释 - 这是我的解决方案
Thanks to GBegan's explanation - here is my solution