DES、AES、RSA、Base64、MD5加密原理介绍,代码实现

关于网络安全的数据加密部分,本来打算总结一篇博客搞定,没想到东西太多,这已是第三篇了,而且这篇写了多次,熬了多次夜,真是again and again。三篇起个名字:数据加密三部曲,前两部链接如下:

  1. 整体介绍:网络安全——数据的加密与签名,RSA介绍

github下载地址

https://github.com/mddios/EncryptionTools

除了RSA外,代码提供两种加解密方法:

一、DES对称加密

关于DES 3DES加密解密原理不再介绍,现在已经用的不多,如果你的项目还在使用DES加密,还是赶快换吧,换做AES或者更强的非对称RSA加密。

另外它与AES有很多的相似性,也可以参照AES介绍。下面是具体的用法。

对"123"加密,密钥为16进制的3031323334353637(01234567)

使用电脑终端:

echo -n "123" | openssl enc -des-ecb -a -K 3031323334353637

结果:
MV5dUGKtzbM=

代码加密解密使用:

首先引入头文件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;

二、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,16、24、32字节,转换为16进制字符串长度为32、48、64,长度错误将抛出异常
 @return 加密结果为base64编码
 */
- (NSString *)aesECBEncryptWithHexKey:(NSString *)key;

/**
 AES-ECB模式加密
 @param key 字符串形式,密钥支持128 192 256bit,16、24、32字节,长度错误将抛出异常
 @return 加密结果为base64编码
 */
- (NSString *)aesECBEncryptWithKey:(NSString *)key;

/**
 AES-ECB模式加密
 @param key 密钥支持128 192 256bit,16、24、32字节,长度错误将抛出异常
 */
- (NSData *)aesECBEncryptWithDataKey:(NSData *)key;

/*
 ECB模式解密,返回base64编码
 */
- (NSString *)aesECBDecryptWithHexKey:(NSString *)key;

/*
 ECB模式解密,返回NSData
 */
- (NSData *)aesECBDecryptWithDataKey:(NSData *)key;

CBC(Cipher Block Chaining,加密块链)模式

CBC模式

是一种循环模式,也将要加密的数据分割为长度相等的组(不足补齐,补齐方式下文介绍),前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度,会比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,16、24、32字节,转换为16进制字符串长度为32、48、64,长度错误将抛出异常
 @param iv 进制字符串形式;初始化向量iv为16字节。如果为nil,则初始化向量为0
 @return 加密结果为base64编码
 */
- (NSString *)aesEncryptWithHexKey:(NSString *)key hexIv:(NSString *)iv;

/**
 AES-CBC模式加密,默认模式
 @param key 密钥支持128 192 256bit,16、24、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,16、24、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,16、24、32字节,长度错误将抛出异常
 @param iv 进制字符串形式;初始化向量iv为16字节。如果为nil,则初始化向量为0
 */
- (NSString *)aesBase64StringDecryptWithHexKey:(NSString *)key hexIv:(NSString *)iv;

/**
 AES-CBC模式解密
 @param key 密钥支持128 192 256bit,16、24、32字节,长度错误将抛出异常
 @param iv 初始化向量iv为16字节。如果为nil,则初始化向量为0
 */
+ (NSData *)aesDecryptWithData:(NSData *)data dataKey:(NSData *)key dataIv:(NSData *)iv;

三、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-----,也可以不加,程序会自动处理。

四、实际使用

选择哪种算法当然是根据自己的需求来定

  • 如果不是关键的数据可以使用DES加密,或者Base64编码不直接看到数据即可,这样速度快
  • 稍微重要的数据,可以用AES加密,一定要保护好密钥
  • 关于钱、用户登陆之类的比较重要,数据量也少,可以使用RSA加密

另外,我们也可以对称加密和非对称加密结合使用,对数据进行AES或DES加密,AES或DES的密钥随机生成,并使用RSA将其加密。对方收到信息后,先RSA解密得到密钥,然后在解密得到加密的数据。这样的话,随机算法就比较重要。

五、关于Padding

  • 数据长度

AES和DES在ECB或者CBC模式下,要加密的数据必须是分组长度的整数倍,比如AES是128位16字节,而DES是64位8字节,那么加密数据必须是16(AES)或者8(DES)的整数倍,如果不是那么就需要填充(pad)。

  • 密钥长度

不像数据长度必须是block的整数倍,密钥长度是固定的。

AES有三种:128、192、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模式有)

另外,默认pad为PKCS5Padding

如果想对openssl有更详细的了解,可以参考 赵春平写的《Openssl编程》里面有很多实用东西,另外也将书的pdf格式上传到了github工程里面,链接见文章最后

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容