NSString+Hash.h
#import <Foundation/Foundation.h>
@interface NSString (Hash)
#pragma mark - 散列函數
/**
* 計算MD5散列結果
*
* 終端測試命令:
* @code
* md5 -s "string"
* @endcode
*
* <p>提示:隨著 MD5 碰撞生成器的出現,MD5 算法不應被用于任何軟件完整性檢查或代碼簽名的用途培愁。<p>
*
* @return 32個字符的MD5散列字符串
*/
- (NSString *)md5String;
/**
* 計算SHA1散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha1
* @endcode
*
* @return 40個字符的SHA1散列字符串
*/
- (NSString *)sha1String;
/**
* 計算SHA256散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha256
* @endcode
*
* @return 64個字符的SHA256散列字符串
*/
- (NSString *)sha256String;
/**
* 計算SHA 512散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha512
* @endcode
*
* @return 128個字符的SHA 512散列字符串
*/
- (NSString *)sha512String;
#pragma mark - HMAC 散列函數
/**
* 計算HMAC MD5散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl dgst -md5 -hmac "key"
* @endcode
*
* @return 32個字符的HMAC MD5散列字符串
*/
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
/**
* 計算HMAC SHA1散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha1 -hmac "key"
* @endcode
*
* @return 40個字符的HMAC SHA1散列字符串
*/
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
/**
* 計算HMAC SHA256散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha256 -hmac "key"
* @endcode
*
* @return 64個字符的HMAC SHA256散列字符串
*/
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
/**
* 計算HMAC SHA512散列結果
*
* 終端測試命令:
* @code
* echo -n "string" | openssl sha -sha512 -hmac "key"
* @endcode
*
* @return 128個字符的HMAC SHA512散列字符串
*/
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
#pragma mark - 文件散列函數
/**
* 計算文件的MD5散列結果
*
* 終端測試命令:
* @code
* md5 file.dat
* @endcode
*
* @return 32個字符的MD5散列字符串
*/
- (NSString *)fileMD5Hash;
/**
* 計算文件的SHA1散列結果
*
* 終端測試命令:
* @code
* openssl sha -sha1 file.dat
* @endcode
*
* @return 40個字符的SHA1散列字符串
*/
- (NSString *)fileSHA1Hash;
/**
* 計算文件的SHA256散列結果
*
* 終端測試命令:
* @code
* openssl sha -sha256 file.dat
* @endcode
*
* @return 64個字符的SHA256散列字符串
*/
- (NSString *)fileSHA256Hash;
/**
* 計算文件的SHA512散列結果
*
* 終端測試命令:
* @code
* openssl sha -sha512 file.dat
* @endcode
*
* @return 128個字符的SHA512散列字符串
*/
- (NSString *)fileSHA512Hash;
@end
NSString+Hash.m
#import "NSString+Hash.h"
#import <CommonCrypto/CommonCrypto.h>
@implementation NSString (Hash)
#pragma mark - 散列函數
- (NSString *)md5String {
const char *str = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)sha1String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)sha256String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)sha512String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - HMAC 散列函數
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - 文件散列函數
#define FileHashDefaultChunkSizeForReadingData 4096
- (NSString *)fileMD5Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_MD5_CTX hashCtx;
CC_MD5_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)fileSHA1Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA1_CTX hashCtx;
CC_SHA1_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)fileSHA256Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA256_CTX hashCtx;
CC_SHA256_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)fileSHA512Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA512_CTX hashCtx;
CC_SHA512_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - 助手方法
/**
* 返回二進制 Bytes 流的字符串表示形式
*
* @param bytes 二進制 Bytes 數組
* @param length 數組長度
*
* @return 字符串表示形式
*/
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < length; i++) {
[strM appendFormat:@"%02x", bytes[i]];
}
return [strM copy];
}
@end