目錄
一、HASH概述
Hash,一般翻譯做“散列”,也有直接音譯為“哈希”的,就是把任意長(zhǎng)度的輸入通過散列算法變換成固定長(zhǎng)度的輸出,該輸出就是散列值。這種轉(zhuǎn)換是一種壓縮映射,也就是,散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會(huì)散列成相同的輸出(Hash碰撞),所以不可能從散列值來(lái)確定唯一的輸入值。簡(jiǎn)單的說就是一種將任意長(zhǎng)度的消息壓縮到某一固定長(zhǎng)度的消息摘要的函數(shù)。
1.1 常見的Hash算法
- MD5
- SHA1、SHA265、SHA512
1.2 Hash的特點(diǎn)
- 算法是公開的
- 對(duì)相同數(shù)據(jù)運(yùn)算,得到的結(jié)果是一樣的
- 對(duì)不同數(shù)據(jù)運(yùn)算,如MD5得到的結(jié)果默認(rèn)是128位(2^128),
32個(gè)字符(16進(jìn)制標(biāo)識(shí):16^32)。 - Hash結(jié)果
無(wú)法逆運(yùn)算,因此Hash不能作為加密算法。 - 信息摘要,信息“
指紋”,是用來(lái)做數(shù)據(jù)識(shí)別的。
1.3 Hash用途
- 用戶密碼的加密
- 搜索引擎:關(guān)鍵詞Hash相加
- 版權(quán):網(wǎng)站保存原文件的Hash值,供用戶下載的文件加了鹽,Hash不一樣。網(wǎng)盤保存的文件通過Hash值去重(同時(shí)也要防止Hash碰撞)。文件修改文件名和文件后綴不會(huì)改變Hash值(壓縮/Base64可以改變Hash值)。
- 數(shù)字簽名
二、用戶密碼加密
通過運(yùn)用HASH算法,給用戶的密碼進(jìn)行加密。
用戶密碼加密方式
- 直接使用MD5
- MD5加鹽
- HMAC加密方案
- 添點(diǎn)東西
思考:直接使用RSA加密傳輸用戶密碼的優(yōu)缺點(diǎn)?
- 優(yōu)點(diǎn):在網(wǎng)絡(luò)傳輸泄露的風(fēng)險(xiǎn)低
- 缺點(diǎn):服務(wù)端收到加密后的密碼解密明文保存到數(shù)據(jù)庫(kù)中非常不安全。
- 如果服務(wù)端不解密保存到數(shù)據(jù)庫(kù)的就是密文,那么黑客直接抓包拿到請(qǐng)求中的密文也能繞過RSA解密。
- RSA中的公鑰和私鑰對(duì)程序員是公開的,程序員的泄露也是很大的風(fēng)險(xiǎn)。
HASH加密用戶密碼
HASH加密用戶密碼后服務(wù)器中就不會(huì)出現(xiàn)明文密碼了
#import "NSString+Hash.h" --->文末
NSString *pwd = @"123456";
pwd = pwd.md5String;
NSLog(@"現(xiàn)在的密碼是:%@",pwd);//e10adc3949ba59abbe56e057f20f883e
存在的問題:通過查詢HASH值可以查詢出很多明文。查詢網(wǎng)址

改進(jìn):加鹽
/* 加鹽 */
static NSString *salt = @"LKSJDFLKJ&^&@@";
NSString *pwd = @"123456";
pwd = [pwd stringByAppendingString:salt].md5String;
NSLog(@"現(xiàn)在的密碼是:%@",pwd);//2359298f49af5695a4b846e95bdea467
存在的問題:固定鹽對(duì)開發(fā)者的依賴很大
HAMC:服務(wù)器發(fā)鹽
NSString *pwd = @"123456";
//HMAC 加密方式!! KEY 由服務(wù)器提供。 給定hmac一個(gè)Key,對(duì)明文進(jìn)行兩次散列
//一個(gè)賬號(hào),一個(gè)KEY!!
pwd = [pwd hmacMD5StringWithKey:@"differ"];
存在的問題:可以直接使用Hash值進(jìn)行登錄
HAMC+時(shí)間戳

三、數(shù)字簽名
為什么用簽名這個(gè)詞.因?yàn)槔贤庀矚g用支票,支票上面的簽名能夠證明這玩意是你的.那么數(shù)字簽名顧名思義,就是用于鑒別數(shù)字信息的方法
- 為了防止傳輸中的數(shù)據(jù)被篡改需要將
數(shù)據(jù)和數(shù)據(jù)的Hash值一起傳遞給客戶端 - 為了防止
數(shù)據(jù)和數(shù)據(jù)的Hash值同時(shí)被篡改,數(shù)據(jù)的Hash值通過RSA再加密一次
四、總結(jié)
- RSA終端代碼、RSA代碼演示。
- RSA的特點(diǎn)
- RSA的安全系數(shù)非常高(因?yàn)檎麄€(gè)業(yè)務(wù)邏輯非常安全)
- 加密效率非常低(不能做大數(shù)據(jù)加密)
- 用來(lái)加密關(guān)鍵數(shù)據(jù)!(對(duì)稱加密的Key,數(shù)字簽名中的Hash值)
- HASH
- 不可逆運(yùn)算
- 相同的數(shù)據(jù)結(jié)果相同
- 不同的數(shù)據(jù)長(zhǎng)度相同
- 一般用于做數(shù)據(jù)的識(shí)別(密碼、版權(quán)、百度云數(shù)據(jù)識(shí)別)
- 密碼加密
- HMAC (比較好的方案)
- HASH+時(shí)間戳。這樣的方式,每次加密結(jié)果不一樣(受時(shí)間的影響比較大)
- 數(shù)字簽名(重點(diǎn)! ! )
- 算法: RSA + HASH
- 目的:驗(yàn)證數(shù)據(jù)的完整性,不被篡改!
- 邏輯:1.將原始數(shù)據(jù)進(jìn)行HASH;2.使用RSA加密HASH值(這部分?jǐn)?shù)據(jù)就是原始數(shù)據(jù)的簽名信息)3.將原始數(shù)據(jù)+數(shù)字簽名 一起打包發(fā)送
NSString+Hash.h
#import <Foundation/Foundation.h>
@interface NSString (Hash)
#pragma mark - 散列函數(shù)
/**
* 計(jì)算MD5散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* md5 -s "string"
* @endcode
*
* <p>提示:隨著 MD5 碰撞生成器的出現(xiàn),MD5 算法不應(yīng)被用于任何軟件完整性檢查或代碼簽名的用途。<p>
*
* @return 32個(gè)字符的MD5散列字符串
*/
- (NSString *)md5String;
/**
* 計(jì)算SHA1散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha1
* @endcode
*
* @return 40個(gè)字符的SHA1散列字符串
*/
- (NSString *)sha1String;
/**
* 計(jì)算SHA256散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha256
* @endcode
*
* @return 64個(gè)字符的SHA256散列字符串
*/
- (NSString *)sha256String;
/**
* 計(jì)算SHA 512散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha512
* @endcode
*
* @return 128個(gè)字符的SHA 512散列字符串
*/
- (NSString *)sha512String;
#pragma mark - HMAC 散列函數(shù)
/**
* 計(jì)算HMAC MD5散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl dgst -md5 -hmac "key"
* @endcode
*
* @return 32個(gè)字符的HMAC MD5散列字符串
*/
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
/**
* 計(jì)算HMAC SHA1散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha1 -hmac "key"
* @endcode
*
* @return 40個(gè)字符的HMAC SHA1散列字符串
*/
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
/**
* 計(jì)算HMAC SHA256散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha256 -hmac "key"
* @endcode
*
* @return 64個(gè)字符的HMAC SHA256散列字符串
*/
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
/**
* 計(jì)算HMAC SHA512散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* echo -n "string" | openssl sha512 -hmac "key"
* @endcode
*
* @return 128個(gè)字符的HMAC SHA512散列字符串
*/
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
#pragma mark - 文件散列函數(shù)
/**
* 計(jì)算文件的MD5散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* md5 file.dat
* @endcode
*
* @return 32個(gè)字符的MD5散列字符串
*/
- (NSString *)fileMD5Hash;
/**
* 計(jì)算文件的SHA1散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* openssl sha1 file.dat
* @endcode
*
* @return 40個(gè)字符的SHA1散列字符串
*/
- (NSString *)fileSHA1Hash;
/**
* 計(jì)算文件的SHA256散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* openssl sha256 file.dat
* @endcode
*
* @return 64個(gè)字符的SHA256散列字符串
*/
- (NSString *)fileSHA256Hash;
/**
* 計(jì)算文件的SHA512散列結(jié)果
*
* 終端測(cè)試命令:
* @code
* openssl sha512 file.dat
* @endcode
*
* @return 128個(gè)字符的SHA512散列字符串
*/
- (NSString *)fileSHA512Hash;
@end
NSString+Hash.m
#import "NSString+Hash.h"
#import <CommonCrypto/CommonCrypto.h>
@implementation NSString (Hash)
#pragma mark - 散列函數(shù)
- (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 散列函數(shù)
- (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 - 文件散列函數(shù)
#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 - 助手方法
/**
* 返回二進(jìn)制 Bytes 流的字符串表示形式
*
* @param bytes 二進(jìn)制 Bytes 數(shù)組
* @param length 數(shù)組長(zhǎng)度
*
* @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