iOS 編碼(Base64) + 雜湊摘要(MD5+SHA)
一、編碼演算法
(1)Base64編碼
在MIME格式的電子郵件中,base64可以用來將binary的位元組序列資料編碼成ASCII字元序列構成的文字。使用時,在傳輸編碼方式中指定base64。使用的字元包括大小寫字母各26個,加上10個數字,和加號“+”,斜槓“/”,一共64個字元,等號“=”用來作為字尾用途。
完整的base64定義可見 RFC1421和 RFC2045。編碼後的資料比原始資料略長,為原來的4/3。在電子郵件中,根據RFC822規定,每76個字元,還需要加上一個回車換行。可以估算編碼後資料長度大約為原長的135.1%。
轉換的時候,將三個byte的資料,先後放入一個24bit的緩衝區中,先來的byte佔高位。資料不足3byte的話,於緩衝區中剩下的Bit用0補足。然後,每次取出6個bit,按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字元作為編碼後的輸出。不斷進行,直到全部輸入資料轉換完成。
如果最後剩下兩個輸入資料,在編碼結果後加1個“=”;如果最後剩下一個輸入資料,編碼結果後加2個“=”;如果沒有剩下任何資料,就什麼都不要加,這樣才可以保證資料還原的正確性。
(2)UrlEncode編碼
百分號編碼(Percent-encoding), 也稱作URL編碼(URL encoding), 是特定上下文的統一資源定位符 (URI)的編碼機制. 實際上也適用於統一資源標誌符(URI)的編碼. 也用於為"application/x-www-form-urlencoded" MIME準備資料, 因為它用於通過HTTP的請求操作(request)提交HTML表單資料。
URI所允許的字元分作保留與未保留. 保留字元是那些具有特殊含義的字元. 例如, 斜線字元用於URL (或者更一般的, URI)不同部分的分界符. 未保留字元沒有這些特殊含義. 百分號編碼把保留字元表示為特殊字元序列. 上述情形隨URI與URI的不同版本規格會有輕微的變化。
部分轉換規則如下:
空格 | ! | # | $ | % | + | @ | : | = | ? |
%20 | %21 | %23 | %24 | %25 | %2B | %40 | %3A | %3D | %3F |
(3)BCD碼
8421碼是BCD程式碼中最常用的一種。在這種編碼方式中每一位二值程式碼的1都是代表一個固定數值,把每一位的1代表的十進位制數加起來,得到的結果就是它所代表的十進位制數碼。由於程式碼中從左到右每一位的1分別表示8,4,2,1,所以把這種程式碼叫做8421程式碼。每一位的1代表的十進位制數稱為這一位的權。8421碼中的每一位的權是固定不變的,它屬於恆權程式碼。
二、雜湊摘要(Hash)
(1)MD5
Message Digest Algorithm MD5(中文名為訊息摘要演算法第五版)為電腦保安領域廣泛使用的一種雜湊函式,用以提供訊息的完整性保護。
MD5即Message-Digest Algorithm 5(資訊-摘要演算法5),用於確保資訊傳輸完整一致。是計算機廣泛使用的雜湊演算法之一(又譯摘要演算法、雜湊演算法),主流程式語言普遍已有MD5實現。將資料(如漢字)運算為另一固定長度值,是雜湊演算法的基礎原理,MD5的前身有MD2、MD3和MD4。
MD5演算法具有以下特點:
1、壓縮性:任意長度的資料,算出的MD5值長度都是固定的。
2、容易計算:從原資料計算出MD5值很容易。
3、抗修改性:對原資料進行任何改動,哪怕只修改1個位元組,所得到的MD5值都有很大區別。
4、強抗碰撞:已知原資料和其MD5值,想找到一個具有相同MD5值的資料(即偽造資料)是非常困難的。
MD5的作用是讓大容量資訊在用數字簽名軟體簽署私人金鑰前被"壓縮"成一種保密的格式(就是把一個任意長度的位元組串變換成一定長的十六進位制數字串)。
(2)SHA
安全雜湊演算法(Secure Hash Algorithm)主要適用於數字簽名標準(Digital Signature Standard DSS)裡面定義的數字簽名演算法(Digital Signature Algorithm DSA)。對於長度小於2^64位的訊息,SHA1會產生一個160位的訊息摘要。該演算法經過加密專家多年來的發展和改進已日益完善,並被廣泛使用。該演算法的思想是接收一段明文,然後以一種不可逆的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預對映或資訊),並把它們轉化為長度較短、位數固定的輸出序列即雜湊值(也稱為資訊摘要或資訊認證程式碼)的過程。雜湊函式值可以說是對明文的一種“指紋”或是“摘要”所以對雜湊值的數字簽名就可以視為對此明文的數字簽名。
(3)MD5與SHA1的區別
因為二者均由MD4匯出,SHA-1和MD5彼此很相似。相應的,他們的強度和其他特性也是相似,但還有以下幾點不同:
1、對強行攻擊的安全性:最顯著和最重要的區別是SHA-1摘要比MD5摘要長32 位。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對MD5是2^128數量級的操作,而對SHA-1則是2^160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。
2、對密碼分析的安全性:由於MD5的設計,易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
3、速度:在相同的硬體上,SHA-1的執行速度比MD5慢。
(4)SHA-1停止計劃
2005年,密碼學家就證明SHA-1的破解速度比預期提高了2000倍,雖然破解仍然是極其困難和昂貴的,但隨著計算機變得越來越快和越來越廉價,SHA-1演算法的安全性也逐年降低,已被密碼學家嚴重質疑,希望由安全強度更高的SHA-2替代它。
微軟第一個宣佈了SHA-1棄用計劃,對於SSL證書和程式碼簽名證書,微軟設定了不同的替換時間表:
1、所有Windows受信任的根證書頒發機構(CA)從2016年1月1日起必須停止簽發新的SHA-1簽名演算法SSL證書和程式碼簽名證書;
2、對於SSL證書,Windows將於2017年1月1日起停止支援SHA1證書。也就是說:任何在之前簽發的SHA-1證書必須替換成SHA-2證書;
3、對於程式碼簽名證書,Windows將於2016年1月1日停止接受沒有時間戳的SHA-1簽名的程式碼和SHA-1證書。也就是說,Windows仍然接受在2016年1月1日之前使用SAH-1簽名的已經加上RFC3161時間戳的程式碼,直到微軟認為有可能出現SHA-1攻擊時。
Google官方部落格宣佈,將在Chrome瀏覽器中逐漸降低SHA-1證書的安全指示,逐步停止對使用SHA-1雜湊演算法證書的支援。近日,Chrome 39新版本 PC 端釋出,在部分作業系統下,該版本瀏覽器中已開始出現“該網站使用的安全設定已過期” 提示,在接下來的6個月內會變得越來越嚴格。最終,使用了有效期至2016年的SHA-1證書的站點可能會被給予黃色警告。
Mozilla也做了同樣的決定,在其對外公佈近期更新計劃中表示:“現在依然有不少網站使用基於 SHA-1簽名的 SSL證書,所以我們決定加入微軟和谷歌的陣營,認為應在 2016 年 1 月 1 日前停止發放 SHA-1 證書,在 2017 年 1 月1 日後不再信任此證書。”
三、程式碼實現(Base64 + MD5 + SHA)
//
// main.m
// CryptoDemo
//
// Created by 555chy on 6/17/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
//#import <CommonCrypto/CommonCrypto.h>
#define G_KEY @""
#define G_IV @""
#define G_SECRET_KEY_LENGTH 24
//ios的base64編碼有兩種方式(使用ios7系統自帶的編碼庫和GMTBase64兩種方式),這裡是用的是系統自帶的方法
NSString* base64Encode(const char* originalCStr, NSInteger len) {
NSData *originalData = [NSData dataWithBytes:originalCStr length:len];
/*
typedef NS_OPTIONS(NSUInteger, NSDataBase64EncodingOptions) {
// Use zero or one of the following to control the maximum line length after which a line ending is inserted. No line endings are inserted by default.
NSDataBase64Encoding64CharacterLineLength = 1UL << 0,
NSDataBase64Encoding76CharacterLineLength = 1UL << 1,
// Use zero or more of the following to specify which kind of line ending is inserted. The default line ending is CR LF.
NSDataBase64EncodingEndLineWithCarriageReturn = 1UL << 4,
NSDataBase64EncodingEndLineWithLineFeed = 1UL << 5,
} NS_ENUM_AVAILABLE(10_9, 7_0);
*/
NSData *base64Data = base64Data = [originalData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
return [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
}
NSString* base64Decode(NSString* encodedBase64Str) {
NSData *base64Data = [[NSData alloc] initWithBase64EncodedString:encodedBase64Str options:NSDataBase64DecodingIgnoreUnknownCharacters];
return [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
}
//加密出啦的是一個32位的16進位制序列
NSString* md5Hash(NSString* originalStr, BOOL is16Or32) {
unsigned char md5CStr[CC_MD5_DIGEST_LENGTH];
//const char *cOriginalStr = [originalStr cStringUsingEncoding:NSUTF8StringEncoding];
const char *cOriginalStr = [originalStr UTF8String];
CC_MD5(cOriginalStr, (CC_LONG)strlen(cOriginalStr), md5CStr);
//NSMutableString *md5Str = [[NSMutableString alloc] init];
NSMutableString *md5Str = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
for(int i=0;i<CC_MD5_DIGEST_LENGTH;i++) {
[md5Str appendFormat:@"%02x", md5CStr[i]];
}
if(is16Or32) {
//return [[md5Str substringToIndex:24] substringFromIndex:8];
return [[md5Str substringFromIndex:8] substringToIndex:16];
}
return md5Str;
}
//SHA
/*
16進位制序列位數 位元組數 位元數
CC_SHA1 40 20 160
CC_SHA256 64 32 256
CC_SHA384 96 48 384
CC_SHA512 128 64 512
*/
NSString* shaHash(NSString* originalStr, unsigned char* (*CC_SHAX)(const void *data, CC_LONG len, unsigned char *md), unsigned int shaDigestLength) {
unsigned char sha1CStr[shaDigestLength];
//const char *cOriginalStr = [originalStr cStringUsingEncoding:NSUTF8StringEncoding];
const char *cOriginalStr = [originalStr UTF8String];
CC_SHAX(cOriginalStr, (CC_LONG)strlen(cOriginalStr), sha1CStr);
//NSMutableString *sha1Str = [[NSMutableString alloc] init];
NSMutableString *sha1Str = [NSMutableString stringWithCapacity:shaDigestLength*2];
for(int i=0;i<shaDigestLength;i++) {
[sha1Str appendFormat:@"%02x", sha1CStr[i]];
}
return sha1Str;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSString *originalStr = @"welcome to chy龍神的部落格";
//NSString *originalStr = @"歡迎光臨JerryVon的部落格";
// const char* originalCstr = [originalStr cStringUsingEncoding:NSUTF8StringEncoding];
const char *originalCstr = [originalStr UTF8String];
NSString *base64EncodeStr = base64Encode(originalCstr, strlen(originalCstr));
NSString *base64DecodeStr = base64Decode(base64EncodeStr);
NSLog(@"originalStr = %@", originalStr);
NSLog(@"base64EncodeStr = %@", base64EncodeStr);
NSLog(@"base64DecodeStr = %@", base64DecodeStr);
NSString *md5Hash16Str = md5Hash(originalStr, YES);
NSString *md5Hash32Str = md5Hash(originalStr, NO);
NSLog(@"md5Hash16Str = %@", md5Hash16Str);
NSLog(@"md5Hash32Str = %@", md5Hash32Str);
NSString *sha1HashStr = shaHash(originalStr, CC_SHA1, CC_SHA1_DIGEST_LENGTH);
NSString *sha256HashStr = shaHash(originalStr, CC_SHA256, CC_SHA256_DIGEST_LENGTH);
NSString *sha384HashStr = shaHash(originalStr, CC_SHA384, CC_SHA384_DIGEST_LENGTH);
NSString *sha512HashStr = shaHash(originalStr, CC_SHA512, CC_SHA512_DIGEST_LENGTH);
NSLog(@"sha1HashStr = %@", sha1HashStr);
NSLog(@"sha25HashStr = %@", sha256HashStr);
NSLog(@"sha384HashStr = %@", sha384HashStr);
NSLog(@"sha512HashStr = %@", sha512HashStr);
}
return 0;
}
四、執行結果
五、第三方驗證