加密原理介紹,代碼實現DES、AES、RSA、Base6四、MD5

閱讀目錄html

關於網絡安全的數據加密部分,原本打算總結一篇博客搞定,沒想到東西太多,這已經是第三篇了,並且這篇寫了屢次,熬了屢次夜,真是again and again。起個名字:數據加密三部曲,前兩部連接以下:ios

  1. 總體介紹:網絡安全——數據的加密與簽名,RSA介紹
  2. 編碼與哈希實現:網絡安全——Base64編碼、MD五、SHA1-SHA5十二、HMAC(SHA1-SHA512)哈希
  3. 本篇DES、AES、RSA加密的介紹與實現

github下載地址

https://github.com/mddios/EncryptionToolsnginx

代碼提供兩種加解密方法:git

1、DES對稱加密

關於DES 3DES加密解密原理再也不介紹,如今已經用的很少,若是你的項目還在使用DES加密,仍是趕快換吧,換作AES或者更強的非對稱RSA加密。github

另外它與AES有不少的類似性,也能夠參照AES介紹。下面是具體的用法。算法

對"123"加密,密鑰爲16進制的3031323334353637(01234567)api

使用電腦終端:安全

echo -n "123" | openssl enc -des-ecb -a -K 3031323334353637 結果: MV5dUGKtzbM=

代碼加密解密使用:bash

首先引入頭文件NSString+Encryption.h /* DES加密 key爲NSString形式 結果返回base64編碼 */ - (NSString *)desEncryptWithKey:(NSString *)key; /* DES加密 key爲NSData形式 結果返回NSData */ - (NSData *)desEncryptWithDataKey:(NSData *)key; #pragma mark - DES解密 /* DES解密,字符串必須爲base64格式,key爲字符串形式 */ - (NSString *)desDecryptWithKey:(NSString *)key; /* DES解密 */ + (NSData *)desDecryptWithData:(NSData *)data dataKey:(NSData *)key;

2、AES對稱加密

AES是高級加密標準Advanced Encryption Standard的縮寫,有多種模式,下面介紹使用最多的兩種服務器

ECB(Electronic Code Book,電子密碼本)模式

是一種基礎的加密方式,要加密的數據被分割成分組長度相等的塊(不足補齊,補齊方式下文介紹),而後單獨的一個個組加密,合在一塊兒輸出組成密文。

電腦終端:

echo -n "123" | openssl enc -aes-128-ecb -a -K 30313233343536373839414243444546 加密結果: 0b6ikfq9CQs11aSCnNXIog==

代碼加密解密使用:

首先引入頭文件NSString+Encryption.h /** AES-ECB模式加密 @param key Hex形式,密鑰支持128 192 256bit,1六、2四、32字節,轉換爲16進制字符串長度爲3二、4八、64,長度錯誤將拋出異常 @return 加密結果爲base64編碼 */ - (NSString *)aesECBEncryptWithHexKey:(NSString *)key; /** AES-ECB模式加密 @param key 字符串形式,密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 @return 加密結果爲base64編碼 */ - (NSString *)aesECBEncryptWithKey:(NSString *)key; /** AES-ECB模式加密 @param key 密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 */ - (NSData *)aesECBEncryptWithDataKey:(NSData *)key; /* ECB模式解密,返回base64編碼 */ - (NSString *)aesECBDecryptWithHexKey:(NSString *)key; /* ECB模式解密,返回NSData */ - (NSData *)aesECBDecryptWithDataKey:(NSData *)key;

CBC(Cipher Block Chaining,加密塊鏈)模式

http://7xs4tc.com1.z0.glb.clouddn.com/cipher01.png

是一種循環模式,也將要加密的數據分割爲長度相等的組(不足補齊,補齊方式下文介紹),前一個分組的密文和當前分組的明文異或操做後再加密,這樣作的目的是加強破解難度,會比ECB安全一點。可是也由於他們的關聯性,形成如下三個缺點:

  • 不利於並行計算:很明顯第一組完成才能計算第二組而後第三組。。。
  • 偏差傳遞:也是依次傳遞
  • 須要初始化向量IV:第二組根據第一組的結果來加密,那第一組根據誰呢?那就是須要額外提供初始化向量

能夠在電腦終端(openssl):

echo -n "123" | openssl enc -aes-128-cbc -a -K 30313233343536373839414243444546 -iv 30313233343536373839414243444546 結果: 5IQJlqxa2e5NGzGqqPpoSw==

代碼加密解密使用:

首先引入頭文件NSString+Encryption.h

/** AES-CBC模式加密,默認模式 @param key Hex形式,密鑰支持128 192 256bit,1六、2四、32字節,轉換爲16進制字符串長度爲3二、4八、64,長度錯誤將拋出異常 @param iv 進制字符串形式;初始化向量iv爲16字節。若是爲nil,則初始化向量爲0 @return 加密結果爲base64編碼 */ - (NSString *)aesEncryptWithHexKey:(NSString *)key hexIv:(NSString *)iv; /** AES-CBC模式加密,默認模式 @param key 密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 @param iv 進制字符串形式;初始化向量iv爲16字節。若是爲nil,則初始化向量爲0 @return 加密結果爲base64編碼 */ - (NSString *)aesEncryptWithKey:(NSString *)key iv:(NSString *)iv; /** AES-CBC模式加密,默認模式 @param data 要加密的數據 @param key 密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 @param iv 初始化向量iv爲16字節。若是爲nil,則初始化向量爲0 @return 加密結果爲NSData形式 */ - (NSData *)aesEncryptWithDataKey:(NSData *)key dataIv:(NSData *)iv; /** AES-CBC模式解密,要求NSString爲base64的結果 @param key 密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 @param iv 進制字符串形式;初始化向量iv爲16字節。若是爲nil,則初始化向量爲0 */ - (NSString *)aesBase64StringDecryptWithHexKey:(NSString *)key hexIv:(NSString *)iv; /** AES-CBC模式解密 @param key 密鑰支持128 192 256bit,1六、2四、32字節,長度錯誤將拋出異常 @param iv 初始化向量iv爲16字節。若是爲nil,則初始化向量爲0 */ + (NSData *)aesDecryptWithData:(NSData *)data dataKey:(NSData *)key dataIv:(NSData *)iv;

3、RSA非對稱加密

關於介紹,以前的博客已經給出,具體能夠參考:網絡安全——數據的加密與簽名,RSA介紹

openssl 生成的密鑰PEM文件爲Base64編碼(這裏的Base64格式,長度超過64字符插有換行,生成的私鑰爲PKCS#1格式),下面是具體的openssl生成公私鑰步驟:

  • 1 生成私鑰,1024bit,PKCS1Padding格式,Base64編碼
命令行:openssl genrsa -out rsa_private_key.pem 1024 結果以下: -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDOxoZIsFbFMeR0OWnc/sF5A3Gj0BWsoClQW3BKgvMQ85ZXVCM6 7g6XItl5sSW2EyMaIeQ8tRsM0HI4oCvlOMjSVgdyZmqbUfaZDoDYPW2pDbLqMDr/ o1eKxYpssbAyH6ZDyJeTOEu9yF7XUsIilokzc0D9i+uPc8yp/vLYTPDJEQIDAQAB AoGAFUMevcy8L2zQ9A6PTzU3Cc2L2u9juyuA9A1i/5Z1jhGuLO6u7Llb8LiZqkTH /u/61Q4VHRT2YhvxEteNi/WJ2L+1wTZYWbE/NIHBls4dTDt4aiMGUG2y6uBcFPmB 97sjT3ofcOHVZuFc80ktyhVuvx5osB8obZHbjn+3hn/pIF0CQQDx1bollu3XXL08 YJrS1mpB3F/87HXcxDa0dWUoqBRUCPjqC+8SuxaddPK6RFvkb1UyWJNzQ5Mb3OZt 65/sipdDAkEA2uMWf0ukTRhxiEYhZIJDSaERYeaWFU+mc6mC2//Tcvy7hldBe15n 7UQNKWl7DbI3Z7NmuKPa+rWqwASqtBAHGwJAOav7iW1V6Q8fvd9X7MHfczdn2LxX Wz+bwCti5XA38NZ27fHMoM3nFcPHAu68b1yxl6ESAOHzmihy93HCoLloWwJARodX j2rTJRhUNMHMLrOedNIWZMJE59cDXk9nX/X9rxZqYi4pZlQUDqqXxxk60j3zhlGT Lrl1bMUuoLKgQmbLswJAIfv1Vw18YcEexWPBkn5iKufu0Fo7+Z776lDLYP1kNyQZ eohofAAWYNQvHZ4WTpiIxi2FZ9xIRu+M7smsIs0h2g== -----END RSA PRIVATE KEY-----
  • 2 根據上面的私鑰生成公鑰
命令行:openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout 結果以下: -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOxoZIsFbFMeR0OWnc/sF5A3Gj 0BWsoClQW3BKgvMQ85ZXVCM67g6XItl5sSW2EyMaIeQ8tRsM0HI4oCvlOMjSVgdy ZmqbUfaZDoDYPW2pDbLqMDr/o1eKxYpssbAyH6ZDyJeTOEu9yF7XUsIilokzc0D9 i+uPc8yp/vLYTPDJEQIDAQAB -----END PUBLIC KEY-----
  • 3 將私鑰生成pkcs8格式,可在iOS工程中直接使用
openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt 結果: -----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAM7GhkiwVsUx5HQ5 adz+wXkDcaPQFaygKVBbcEqC8xDzlldUIzruDpci2XmxJbYTIxoh5Dy1GwzQcjig K+U4yNJWB3JmaptR9pkOgNg9bakNsuowOv+jV4rFimyxsDIfpkPIl5M4S73IXtdS wiKWiTNzQP2L649zzKn+8thM8MkRAgMBAAECgYAVQx69zLwvbND0Do9PNTcJzYva 72O7K4D0DWL/lnWOEa4s7q7suVvwuJmqRMf+7/rVDhUdFPZiG/ES142L9YnYv7XB NlhZsT80gcGWzh1MO3hqIwZQbbLq4FwU+YH3uyNPeh9w4dVm4VzzSS3KFW6/Hmiw HyhtkduOf7eGf+kgXQJBAPHVuiWW7ddcvTxgmtLWakHcX/zsddzENrR1ZSioFFQI +OoL7xK7Fp108rpEW+RvVTJYk3NDkxvc5m3rn+yKl0MCQQDa4xZ/S6RNGHGIRiFk gkNJoRFh5pYVT6ZzqYLb/9Ny/LuGV0F7XmftRA0paXsNsjdns2a4o9r6tarABKq0 EAcbAkA5q/uJbVXpDx+931fswd9zN2fYvFdbP5vAK2LlcDfw1nbt8cygzecVw8cC 7rxvXLGXoRIA4fOaKHL3ccKguWhbAkBGh1ePatMlGFQ0wcwus5500hZkwkTn1wNe T2df9f2vFmpiLilmVBQOqpfHGTrSPfOGUZMuuXVsxS6gsqBCZsuzAkAh+/VXDXxh wR7FY8GSfmIq5+7QWjv5nvvqUMtg/WQ3JBl6iGh8ABZg1C8dnhZOmIjGLYVn3EhG 74zuyawizSHa -----END PRIVATE KEY-----

能夠在終端對"123"RSA加密,因爲使用PKCS#1生成隨機碼,因此每次加密結果會不同

echo "123" | openssl rsautl -encrypt -inkey rsa_public_key.pem -pubin | Base64 加密結果(Base64): ZDBtICMxy2JHg6QDqolyAeqBRMseqJQ33tYQRE26c69/dGlS3TJ2xzMRZlsww+NnQH48KVthyCJ6nIhgAvhmAOaG+MvMqhZT/G180euH3OfLX8/VcIWqelxm8IYzA3NRD8n2jWbWoxZHh8Sp3n+YM7vor+8Q3SsFXMuurwT+xPI=

例程RSA加密使用了第三方框架,連接以下:https://github.com/ideawu/Objective-C-RSA,在使用時公鑰能夠直接使用,私鑰須要使用pkcs8格式。公私鑰能夠加-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----,也能夠不加,程序會自動處理。

4、實際使用

選擇哪一種算法固然是根據本身的需求來定

  • 若是不是關鍵的數據可使用DES加密,或者Base64編碼不直接看到數據便可,這樣速度快
  • 稍微重要的數據,能夠用AES加密,必定要保護好密鑰
  • 關於錢、用戶登錄之類的比較重要,數據量也少,可使用RSA加密

另外,咱們也能夠對稱加密和非對稱加密結合使用,對數據進行AES或DES加密,AES或DES的密鑰隨機生成,並使用RSA將其加密。對方收到信息後,先RSA解密獲得密鑰,而後在解密獲得加密的數據。這樣的話,隨機算法就比較重要。

5、關於Padding

  • 數據長度

AES和DES在ECB或者CBC模式下,要加密的數據必須是分組長度的整數倍,好比AES是128位16字節,而DES是64位8字節,那麼加密數據必須是16(AES)或者8(DES)的整數倍,若是不是那麼就須要填充(pad)。

  • 密鑰長度

不像數據長度必須是block的整數倍,密鑰長度是固定的。

AES有三種:12八、19二、256bit

pad的方式有不少種,並且你也能夠自定義,用的比較多的有PKCS7Padding、PKCS1Padding和PKCS5Padding。

  • PKCS7Padding:用十六進制0x07來填充,下面爲一個簡單的實現方法(其實不少加密工具已經實現,這裏只是舉個例子)
// plainData爲要加密的數據,「16」是block大小 while (plainData.length % 16 != 0) { // PKCS7Padding模式 Byte PKCS7Pad = 0x07; [plainData appendData:[[NSData alloc] initWithBytes:&PKCS7Pad length:1]]; }
  • PKCS5Padding:稍麻煩一點,好比須要填充7個字節就填充0x07,須要填充6個字節就是0x06。。。須要填充1個字節就是0x01

加解密雙方必須使用相同的方式,否則解密就會失敗。

關於電腦終端Openssl加密解密命令

對"123"加密,密鑰爲"30313233343536373839414243444546"(16進制,對應ASCII碼爲0~F),初始化向量爲"30313233343536373839414243444546"(16進制,對應ASCII碼爲0~F)

echo -n "123" | openssl enc -aes-128-cbc -a -A -K 30313233343536373839414243444546 -iv 30313233343536373839414243444546

下面對參數作說明:

  • echo -n "123" |:輸出123且不換行,「|」是管道符號,將前面的輸出做爲後面的輸入,即"123"做爲後面要加密的數據。openssl命令是對文件加密,這樣作好處是直接能夠對字符串加密。
  • enc:對稱加密
  • -aes-128-cbc:算法名字模式
  • -a:加密結果進行base64編碼
  • -A:輸出不換行,默認狀況下,base64編碼結果換行
  • -K:後面跟密鑰,16進制形式
  • -iv:初始化向量(CBC模式有)

 

網絡安全——Base64編碼、MD五、SHA1-SHA5十二、HMAC(SHA1-SHA512)哈希

 

聽說今天520是個好日子,爲何我想起的是50二、500、404這些?還好服務器沒事!

1、Base64編碼

Base64編碼要求把3個8位字節(3*8=24)轉化爲4個6位的字節(4*6=24),以後在6位的前面補兩個0,造成8位一個字節的形式,這樣每個字節的有效位爲6位,則取值範圍0~630 ~ (2^6 - 1)。若是最後剩下的字符不到3個字節,則用0填充,輸出字符使用'=',所以咱們看到Base64末尾會有1到2個'='。另外標準還要求每76個字符要插入換行(不過,這個視具體狀況定)。

iOS7以後蘋果有本身的Base64編碼解碼API,NSData的擴展:NSData (NSDataBase64Encoding)

兩種存儲方式

  • 可見字符串形式

爲了保證所輸出的每個編碼字節都是可讀字符,而不是0~63這些數字,Base64製做了一個碼錶,就像ASCII碼錶同樣,每個Base64碼值都有對應的字符。64個可讀字符從0到63非別是A-Z、a-z、0-九、+、/,這也是Base64名字的由來。

  • 以16進制形式

即NSData形式保存,Base64編碼結果爲字符,而這些字符又對應ASCII碼錶的碼值,NSData就是存儲ASCII碼錶的碼值。

下面舉個例子,並以蘋果提供的API來詳細介紹Base64編碼解碼過程:

假設咱們對字符串"123"進行Base64編碼,"123"對應的16進制是313233,二進制爲0011000一、001100十、00110011,將其變爲4*6結果即下表中的第一行。而後根據Base64的碼錶,它們分別對應表中的第二行。那麼"123"編碼的最終結果即爲MTIz,以字符串的形式保存。而後根據MTIz對應ASCII碼值,以NSData形式存儲,如表中的第三行。

轉換爲4*6結果 00001100 00010011 00001000 00110011
Base64對應字符 M T I z
對應ASCII碼值(16進制) 4d 54 49 7a

上面的過程經過代碼實現以下:

// 1 待編碼的原始字符串 NSString *plainStr = @"123"; // 2 將其轉換成NSData保存,那麼"123"對應的ASCII碼錶碼值是3一、3二、33(16進制) NSData *plainData = [plainStr dataUsingEncoding:NSUTF8StringEncoding]; // 3.1 將其進行Base64編碼,且結果以字符串形式保存,對應表中的第二行 NSString *baseStr = [plainData base64EncodedStringWithOptions:0]; // 3.2 將其進行Base64編碼,且結果以NSData形式保存 NSData *base64Data = [plainData base64EncodedDataWithOptions:0];

另外對於參數NSDataBase64EncodingOptions選項,有多種取值

  • NSDataBase64Encoding64CharacterLineLength:每64個字符插入\r或\n
  • NSDataBase64Encoding76CharacterLineLength:每76個字符插入\r或\n,標準中有要求是76個字符要換行,不過具體仍是本身定
  • NSDataBase64EncodingEndLineWithCarriageReturn:插入字符爲\r
  • NSDataBase64EncodingEndLineWithLineFeed:插入字符爲\n

前兩個選項爲是否容許插入字符,以及多少個字符長度插入,兩個能夠選其一或者都不選。後兩個選項表明要插入的具體字符。好比咱們想76個字符後插入一個\r則能夠NSDataBase64Encoding76CharacterLineLength | NSDataBase64EncodingEndLineWithCarriageReturn。而在上面舉的例子中選項爲0,則表明不插入字符。

第三方框架

在iOS7以前咱們通常用的都是第三方框架,好比nicklockwood寫的https://github.com/nicklockwood/Base64還有Google的GTMBase64,雖然蘋果有了本身的實現,可是許多其它的加密框架都用到了它,因此仍是要了解一下,另外它還提供任意長度字符插入\r\n,而蘋果只能是64或76長度。

2、MD五、SHA一、SHA25六、SHA5十二、HMAC實現

主要用於驗證,防止信息被修改。介紹請參照http://www.jianshu.com/p/003b85fd3e36

具體的實現參考第三方框架:https://github.com/kelp404/CocoaSecurity。很是全面,不過不是太方便,好比想要得到MD5結果

NSString *plainStr = @"123"; CocoaSecurityResult *md5 = [CocoaSecurity md5:plainStr]; // 獲取md5結果 NSString *md5Str = md5.hexLower;

不能直接plainStr.MD5Hash就得到字符串形式的結果,這裏我封裝了一個,能夠參見工程中的NSString+Hash類https://github.com/mddios/EncryptionTools,能夠直接對字符串進行操做,相似plainStr.MD5Hash、plainStr.sha1Hash···plainStr.sha256Hash···,很是方便。

好比對@"123"哈希,下面用上面提到的兩種方法舉例:

- (void)hashTest { NSString *plainStr = @"123"; // md5 CocoaSecurityResult *md5 = [CocoaSecurity md5:plainStr]; NSLog(@"md5:%lu---%@---%@",plainStr.md5Hash.length, plainStr.md5Hash,md5.hex); // 40 CocoaSecurityResult *sha1 = [CocoaSecurity sha1:plainStr]; NSLog(@"sha1:%lu---%@---%@",plainStr.sha1Hash.length, plainStr.sha1Hash,sha1.hex); // 56 CocoaSecurityResult *sha224 = [CocoaSecurity sha224:plainStr]; NSLog(@"sha224:%lu---%@---%@",plainStr.sha224Hash.length,plainStr.sha224Hash,sha224.hex); // 64 CocoaSecurityResult *sha256 = [CocoaSecurity sha256:plainStr]; NSLog(@"sha256:%lu---%@---%@",plainStr.sha256Hash.length,plainStr.sha256Hash,sha256.hex); // 96 CocoaSecurityResult *sha384 = [CocoaSecurity sha384:plainStr]; NSLog(@"sha384:%lu---%@---%@",plainStr.sha384Hash.length,plainStr.sha384Hash,sha384.hex); // 128 CocoaSecurityResult *sha512 = [CocoaSecurity sha512:plainStr]; NSLog(@"sha512:%lu---%@---%@",plainStr.sha512Hash.length,plainStr.sha512Hash,sha512.hex); // hmac CocoaSecurityResult *hmacmd5 = [CocoaSecurity hmacMd5:plainStr hmacKey:plainStr]; NSLog(@"hmacmd5:%lu---%@---%@",[plainStr hmacMD5WithKey:plainStr].length,[plainStr hmacMD5WithKey:plainStr],hmacmd5.hex); }
  • 在電腦終端來獲取結果

封裝的代碼中NSString+Hash.h頭文件,有具體列出終端命令方法,以下:

/// 返回結果:32長度 終端命令:md5 -s "123" - (NSString *)md5Hash; /// 返回結果:40長度 終端命令:echo -n "123" | openssl sha -sha1 - (NSString *)sha1Hash; /// 返回結果:56長度 終端命令:echo -n "123" | openssl sha -sha224 - (NSString *)sha224Hash; /// 返回結果:64長度 終端命令:echo -n "123" | openssl sha -sha256 - (NSString *)sha256Hash; /// 返回結果:96長度 終端命令:echo -n "123" | openssl sha -sha384 - (NSString *)sha384Hash; /// 返回結果:128長度 終端命令:echo -n "123" | openssl sha -sha512 - (NSString *)sha512Hash; #pragma mark - HMAC /// 返回結果:32長度 終端命令:echo -n "123" | openssl dgst -md5 -hmac "123" - (NSString *)hmacMD5WithKey:(NSString *)key; /// 返回結果:40長度 echo -n "123" | openssl sha -sha1 -hmac "123" - (NSString *)hmacSHA1WithKey:(NSString *)key; - (NSString *)hmacSHA224WithKey:(NSString *)key; - (NSString *)hmacSHA256WithKey:(NSString *)key; - (NSString *)hmacSHA384WithKey:(NSString *)key; - (NSString *)hmacSHA512WithKey:(NSString *)key;
  • 關於MD5加鹽,只是多了下面第一行
plainStr = [plainStr stringByAppendingString:salt]; NSString *md5Str = plainStr.md5Hash;

github代碼下載地址

https://github.com/mddios/EncryptionTools

相關文章
相關標籤/搜索