復習
1:常見的hash算法
2:hash算法特點:算法公開、不可逆、相同數據md5相同、信息摘要
3:hash算法用途:密碼加密,數字簽名。
4:密碼加密:md5、md5加鹽、Hmac(2次散列)、登錄權限。
5:數字簽名,數字簽名驗證。
6:常見的對稱加密
7:加密模式ecb、cbc
8:vi命令
目錄
一:hash(算列)算法
1:常見的hash算法
2:hash算法特點
3:hash算法用途
4:密碼加密流程、token
5:數字簽名
二:對稱加密
1:常見的對稱加密
2:加密模式ecb、cbc
3:vi命令
正文
一:hash算法
1:hash 哈希(散列)函數,不是加密算法,經常和加密一起使用。
Hash,一般翻譯做“散列”,也有直接音譯為“哈希”的,就是把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值。
MD5
SHA1/256/512
HMAC(加密的方案)
2:算法特點
1:算法公開
2:對相同的數據運算,結果一樣。默認128位二進制進制的數據。32位的16進制。
3:不可逆運算。
4:信息摘要,用來做數據識別。
3:用途
1:用戶密碼的加密(不用rsa加密,數據庫應該存儲密碼,用戶隱私信息(包括密碼)是hash算法)
2:版權
3:數字簽名
4:搜索引擎
備注:hash算法一般是對字符串來操作的。
cmd5可以解開md5的值。
4:用戶密碼加密:
1:直接對密碼進行md5不安全,可以反查詢。
2:MD5 加鹽。靜態字符串。
拼接一個復雜的字符串。
缺點:鹽是固定的,寫死在程序中,一旦泄露就不安全了。
3:Hmac:加密方案。
使用一個秘鑰(key)加密,並且做兩次散列。在實際開發中,這個秘鑰來自服務器。動態鹽。
3.1:一個賬號對應一個key,而且可以更新這個key。
3.2:什么時候客戶端拿到key
首次登陸的時候拿到key。注冊的時候拿到key。
換設備的時候,沒有key,需要驗證的時候。
3.3:對key進行擴展,設備鎖::讓原始設備允許的時候,才可以申請key。
Key是一個權限。有了key才可以登錄。
3.4:目的:保護了用戶的密碼。
4:登錄權限
添加服務器的時間戳(到分鍾級別的時間戳)
(Hmac哈希值+202005211556).MD5用於登錄。
5:數字簽名
對原始數據的hash值用rsa加密。
用hash來驗證數據的完整性,用來判斷數據是否篡改。
發給服務器的數據是:
原始數據+原始數據的hash值的rsa加密值。
數組簽名
數字簽名驗證
二:對稱加密
1:常見加密算法
1.1:DES
1.2:3DES:3對秘鑰,對同一個數據進行3次加密。
1.3:AES(高級密碼標准)
2:對稱機密-加密模式
Ecb:電子密碼本模式
Cbc:密碼分組鏈接模式,后一個密碼塊加密依賴前一個密碼塊的加密。
ECB(Electronic Code Book):電子密碼本模式。每一塊數據,獨立加密。
最基本的加密模式,也就是通常理解的加密,相同的明文將永遠加密成相同的密文,無初始向量,容易受到密碼本重放攻擊,一般情況下很少用。
CBC(Cipher Block Chaining):密碼分組鏈接模式。使用一個密鑰和一個初始化向量[IV]對數據執行加密。
明文被加密前要與前面的密文進行異或運算后再加密,因此只要選擇不同的初始向量,相同的密文加密后會形成不同的密文,這是目前應用最廣泛的模式。CBC加密后的密文是上下文相關的,但明文的錯誤不會傳遞到后續分組,但如果一個分組丟失,后面的分組將全部作廢(同步錯誤)。
CBC可以有效的保證密文的完整性,如果一個數據塊在傳遞是丟失或改變,后面的數據將無法正常解密。
3:終端命令
1: 創建message.txt文件
1.1:vi message.txt
1.2: 輸入i進入編輯模式
1.3:輸入文本內容
1.4:esc退出編輯模式
1.5: :wq 退出編輯模式,並且保存
2:加密message.txt
2.1: ecb模式
openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg.bin
2.2: cbc模式 xxd 查看二進制數據
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg1.bin
三: 代碼
1:hash算法
代碼

#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

#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
使用

#import "ViewController.h" #import "NSString+Hash.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //足夠復雜! static NSString * salt = @"(*(*(DS*YFHIUYF(*&DSFHUS(*AD&"; -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //密碼 NSString * pwd = @"123456"; //MD5 直接加密 e10adc3949ba59abbe56e057f20f883e //不足:不夠安全了。可以反查詢! // pwd = pwd.md5String; //MD5 加鹽 //弊端: 鹽是固定的,寫死在程序里面,一旦泄露就不安全了! // pwd = [pwd stringByAppendingString:salt].md5String; /** HMAC * 使用一個密鑰加密,並且做兩次散列! * 在實際開發中,密鑰(KEY)來自於服務器(動態的)! * 一個賬號,對應一個KEY,而且還可以跟新! */ pwd = [pwd hmacMD5StringWithKey:@"hank"]; NSLog(@"%@",pwd); } @end
2:對稱加密
2.1:對稱加密終端命令
加密
echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
解密
echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
2.2:CCCrypt 函數,des、aes 加密,2中加密模式,秘鑰,11個參數
代碼

#import <Foundation/Foundation.h> #import <CommonCrypto/CommonCrypto.h> /** * 終端測試指令 * * DES(ECB)加密 * $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64 * * DES(CBC)加密 * $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64 * * AES(ECB)加密 * $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64 * * AES(CBC)加密 * $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64 * * DES(ECB)解密 * $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d * * DES(CBC)解密 * $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d * * AES(ECB)解密 * $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d * * AES(CBC)解密 * $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d * * 提示: * 1> 加密過程是先加密,再base64編碼 * 2> 解密過程是先base64解碼,再解密 */ @interface EncryptionTools : NSObject + (instancetype)sharedEncryptionTools; /** @constant kCCAlgorithmAES 高級加密標准,128位(默認) @constant kCCAlgorithmDES 數據加密標准 */ @property (nonatomic, assign) uint32_t algorithm; /** * 加密字符串並返回base64編碼字符串 * * @param string 要加密的字符串 * @param keyString 加密密鑰 * @param iv 初始化向量(8個字節) * * @return 返回加密后的base64編碼字符串 */ - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv; /** * 解密字符串 * * @param string 加密並base64編碼后的字符串 * @param keyString 解密密鑰 * @param iv 初始化向量(8個字節) * * @return 返回解密后的字符串 */ - (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv; @end

#import "EncryptionTools.h" @interface EncryptionTools() @property (nonatomic, assign) int keySize; @property (nonatomic, assign) int blockSize; @end @implementation EncryptionTools + (instancetype)sharedEncryptionTools { static EncryptionTools *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; instance.algorithm = kCCAlgorithmAES; }); return instance; } - (void)setAlgorithm:(uint32_t)algorithm { _algorithm = algorithm; switch (algorithm) { case kCCAlgorithmAES: self.keySize = kCCKeySizeAES128; self.blockSize = kCCBlockSizeAES128; break; case kCCAlgorithmDES: self.keySize = kCCKeySizeDES; self.blockSize = kCCBlockSizeDES; break; default: break; } } - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv { // 設置秘鑰 NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding]; uint8_t cKey[self.keySize]; bzero(cKey, sizeof(cKey)); [keyData getBytes:cKey length:self.keySize]; // 設置iv uint8_t cIv[self.blockSize]; bzero(cIv, self.blockSize); int option = 0; if (iv) { [iv getBytes:cIv length:self.blockSize]; option = kCCOptionPKCS7Padding; } else { option = kCCOptionPKCS7Padding | kCCOptionECBMode; } // 設置輸出緩沖區 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; size_t bufferSize = [data length] + self.blockSize; void *buffer = malloc(bufferSize); // 開始加密 size_t encryptedSize = 0; //加密解密都是它 -- CCCrypt CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, self.algorithm, option, cKey, self.keySize, cIv, [data bytes], [data length], buffer, bufferSize, &encryptedSize); NSData *result = nil; if (cryptStatus == kCCSuccess) { result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize]; } else { free(buffer); NSLog(@"[錯誤] 加密失敗|狀態編碼: %d", cryptStatus); } return [result base64EncodedStringWithOptions:0]; } - (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv { // 設置秘鑰 NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding]; uint8_t cKey[self.keySize]; bzero(cKey, sizeof(cKey)); [keyData getBytes:cKey length:self.keySize]; // 設置iv uint8_t cIv[self.blockSize]; bzero(cIv, self.blockSize); int option = 0; if (iv) { [iv getBytes:cIv length:self.blockSize]; option = kCCOptionPKCS7Padding;//CBC 加密! } else { option = kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密! } // 設置輸出緩沖區 NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0]; size_t bufferSize = [data length] + self.blockSize; void *buffer = malloc(bufferSize); // 開始解密 size_t decryptedSize = 0; /**CCCrypt 對稱加密算法的核心函數(加密/解密) 參數: 1、kCCEncrypt 加密/kCCDecrypt 解密 2、加密算法、默認的 AES/DES 3、加密方式的選項 kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密! kCCOptionPKCS7Padding;//CBC 加密! 4、加密密鑰 5、密鑰長度 6、iv 初始化向量,ECB 不需要指定 7、加密的數據 8、加密的數據長度 9、緩沖區(地址),存放密文的 10、緩沖區的大小 11、加密結果大小 */ CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, self.algorithm, option, cKey, self.keySize, cIv, [data bytes], [data length], buffer, bufferSize, &decryptedSize); NSData *result = nil; if (cryptStatus == kCCSuccess) { result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize]; } else { free(buffer); NSLog(@"[錯誤] 解密失敗|狀態編碼: %d", cryptStatus); } return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; } @end
使用

#import "ViewController.h" #import "EncryptionTools.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; /** AES - ECB */ NSString * key = @"abc"; NSString * encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil]; NSLog(@"加密的結果是:%@",encStr); NSLog(@"解密的結果是:%@",[[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:nil]); /** AES - CBC 加密 */ uint8_t iv[8] = {1,2,3,4,5,6,7,8}; NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)]; NSLog(@"CBC加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:@"abc" iv:ivData]); NSLog(@"解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:key iv:ivData]); } @end
注意
1:hash算法特點用途(密碼加密【hmac雙層加密-token】和數字簽名)
2:對稱加密算法和對稱加密模式ecb、cbc