我正在尝试散列密码并遵循教程。我有#define kSalt @"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"
添加到我的密码,我像这样散列:
NSString *saltedPassword = [NSString stringWithFormat:@"%@%@", self.passwordField.text, kSalt];
NSString *hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
NSData *data = [saltedPassword dataUsingEncoding:NSUTF8StringEncoding];
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
}
else{
NSLog(@"Error");
}
我得到一个"Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'CC_LONG' (aka 'unsigned int')"
警告。谁能给我一些指点,我可能在这里做错了什么?为什么我使用NSASCIIStringEncoding
而不是NSUTF8StringEncoding
的哈希密码字符串?
#define kSalt @"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"
-(NSString*)hashPassword:(NSString*)password {
//salt the password
NSString* saltedPassword = [NSString stringWithFormat:@"%@%@", password, kSalt];
//prepare the hashed storage
NSString* hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
//hash the pass
NSData *data = [saltedPassword dataUsingEncoding: NSUTF8StringEncoding];
if (CC_SHA1([data bytes], (unsigned)[data length], hashedPasswordData))
{
hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
[self promptUserMessage: @"Password can't be sent"];
return @"Error";
}
NSLog(@"saltedPassword: %@",saltedPassword);
NSLog(@"hashedPasswordData: %s",hashedPasswordData);
NSLog(@"data: %@",data);
NSLog(@"hashedPassword: %@",hashedPassword);
return hashedPassword;
}
NSString* hashedPassword1 = [self hashPassword:@"abc"];
你的警告问题很好,值得深入研究如何探索它,因为其他人将来可能会有类似的问题。简短的答案是"将[data length]
更改为(CC_LONG)[data length]
",现在让我们看看为什么。
这是CC_SHA1
的签名:
extern unsigned char *CC_SHA1(const void *data, CC_LONG len, unsigned char *md)
你是这样称呼它的:
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
-length
是这样定义的:
@property NSUInteger length;
NSUInteger
表示"无符号整数,此处理器上的字长"。在32位处理器上,它是32位无符号整数。在64位进程中,它是一个64位无符号整数。
CC_LONG
的定义如下:
typedef uint32_t CC_LONG; /* 32 bit unsigned integer */
所以它总是一个32位无符号整数
这在32位系统上没有问题,但在64位系统上,您将64位数字传递给32位参数。只要实际数字能在32位内,那就行得通。但是编译器并不确定这是真的,并且警告你如果它不是真的,你会得到意外的行为。修复方法是说"是的,我保证这个值将适合32位",你可以通过转换在C中做到这一点。您可以强制转换为一堆东西来摆脱警告,但最好是强制转换为所请求的内容,CC_LONG
。
if (CC_SHA1([data bytes], (CC_LONG)[data length], hashedPasswordData)) {
就NSASCIIStringEncoding
而言,这是一种非常糟糕的转换数据的方式,可能会丢失信息。我很惊讶这还能起作用。NSASCIIStringEncoding
是7位ASCII,所以如果任何一个字节大于127(这是很有可能的),这种编码将失败。我不记得整个编码是否会失败,或者这些字节是否会被丢弃,但无论如何,它都不会是正确的答案。您也不能将其编码为UTF-8,但是一系列随机字节可能不是合法的UTF-8。要将随机数据转换为字符串,需要为此设计一种编码,例如base-64或十六进制。Base-64非常流行,因为它需要更少的字节来编码,同时产生7位ascii安全字符串。查看NSData
上的-base64EncodedData:options:
方法