对称加密方式:明文通过密钥加密得到密文,密文通过密钥解密得到明文。
定义
需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用
对称性加密也称为密钥加密。所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密
因此加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题
算法
采用单钥密码的加密方法,同一个密钥可以同时用来加密和解密,这种加密方法称为对称加密,也称为单密钥加密
常用的对称加密算法:
DES
:数据加密标准,速度较快,适用于加密大量数据的场合(用得少,因为强度不够)3DES
:是基于DES
,对一块数据用3个
不同的密钥进行3次
加密,强度更高AES
:高级加密标准,是下一代的加密算法标准,速度快,安全级别高,支持128
、192
、256
、512
位密钥的加密算法特征:
- 加密方和解密方使用同一个密钥
- 加密解密的速度比较快,适合数据比较长时的使用
- 密钥传输的过程不安全,且容易被破解,密钥管理也比较麻烦
应用模式
ECB
(Electronic Code Book
):电子密码本模式。每一块数据,独立加密
- 最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用
CBC
(Cipher Block Chaining
):密码分组链接模式。使用一个密钥和一个初始化向量iv
对数据执行加密
- 明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。
CBC
加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)CBC
可以有效的保证密文的完整性,如果一个数据块在传递是丢失或改变,后面的数据将无法正常解密
向量
iv
的作用很多加密算法都和几何图形有关
几何图形的变量算法同样具有规律性,但算法的规律结果变幻莫测
例如:一个圆上有无数个点,如果把某一个点视为向量
iv
,加密结果则会有无数种所以将几何算法添加到加密算法中,它的破解难度系数变得更大
案例1:
创建
file.txt
文件,写入以下内容:000000000000 111111111111 222222222222 000000000000 111111111111 222222222222
使用
DES
的ECB
模式加密,输出二进制文件msg1.bin
openssl enc -des-ecb -K 616263 -nosalt -in file.txt -out msg1.bin
616263
:abc
的16进制
的ASCII
码openssl
命令,默认随机加盐,通过-nosalt
参数,取消该策略使用
xxd msg1.bin
命令,以16进制
输出二进制文件00000000: d1f8 0876 7a80 0184 49ca bbb3 aab0 3fc0 ...vz...I.....?. 00000010: d037 d2e2 c336 b854 bb70 0dfa 0725 a619 .7...6.T.p...%.. 00000020: 09a9 fef3 c8f1 9b92 d1f8 0876 7a80 0184 ...........vz... 00000030: 86ae 214a ff02 4f0d d037 d2e2 c336 b854 ..!J..O..7...6.T 00000040: 5fbb c6fa 6c65 a990 5f01 6db1 eee3 133b _...le.._.m....;
打开
file.txt
文件,将第4行
开头的00
改为88
:000000000000 111111111111 222222222222 880000000000 111111111111 222222222222
使用
DES
的ECB
模式加密,输出二进制文件msg2.bin
openssl enc -des-ecb -K 616263 -nosalt -in file.txt -out msg2.bin
使用
xxd msg2.bin
命令,以16进制
输出二进制文件00000000: d1f8 0876 7a80 0184 49ca bbb3 aab0 3fc0 ...vz...I.....?. 00000010: d037 d2e2 c336 b854 bb70 0dfa 0725 a619 .7...6.T.p...%.. 00000020: 1087 3405 8261 0661 69c5 1db2 8613 2255 ..4..a.ai....."U 00000030: 86ae 214a ff02 4f0d d037 d2e2 c336 b854 ..!J..O..7...6.T 00000040: 5fbb c6fa 6c65 a990 5f01 6db1 eee3 133b _...le.._.m....;
对比
msg1.bin
和msg2.bin
二进制内容
- 只有
第3行
的16字节
数据发生变化
案例2:
创建
file.txt
文件,写入以下内容:000000000000 111111111111 222222222222 000000000000 111111111111 222222222222
使用
DES
的CBC
模式加密,输出二进制文件msg1.bin
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in file.txt -out msg1.bin
iv
:向量,必须为8字节
数据使用
xxd msg1.bin
命令,以16进制
输出二进制文件00000000: ca73 66ec 42d1 fcc3 a66c 7f53 0108 8981 .sf.B....l.S.... 00000010: 431d 4fd7 076b caae 9158 a232 e248 6b71 C.O..k...X.2.Hkq 00000020: a9b0 f336 ee43 9b58 f026 a63f 685a b53f ...6.C.X.&.?hZ.? 00000030: 8f53 ecc8 6094 b9e3 eb95 2106 285d 5d65 .S..`.....!.(]]e 00000040: 6887 ac17 5628 d1a1 7915 0d78 3b10 f2d1 h...V(..y..x;...
打开
file.txt
文件,将第4行
开头的00
改为88
:000000000000 111111111111 222222222222 880000000000 111111111111 222222222222
使用
DES
的CBC
模式加密,输出二进制文件msg2.bin
openssl enc -des-ecb -iv 0102030405060708 -K 616263 -nosalt -in file.txt -out msg2.bin
使用
xxd msg2.bin
命令,以16进制
输出二进制文件00000000: ca73 66ec 42d1 fcc3 a66c 7f53 0108 8981 .sf.B....l.S.... 00000010: 431d 4fd7 076b caae 9158 a232 e248 6b71 C.O..k...X.2.Hkq 00000020: 6560 8a18 d121 1576 26bb 7811 9ac9 d586 e`...!.v&.x..... 00000030: bb81 1bd2 796a 5ea3 541d 3cb2 445c a59c ....yj^.T.<.D\.. 00000040: ed74 1437 ad52 f87d ed84 ebe8 d90c 272a .t.7.R.}......'*
对比
msg1.bin
和msg2.bin
二进制内容
- 从
第3行
开头到二进制的结尾,全部数据发生变化
优缺点
对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高
对称加密算法的缺点是在数据传送前,发送方和接收方必须商定好秘钥,然后使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的独一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担
终端命令
命令的管道输出顺序:
- 加密过程是先加密,再
Base64
编码- 解密过程是先
Base64
解码,再解密
案例1:
使用
DES
加解密
ECB
模式加密:echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64 ------------------------- HQr0Oij2kbo=
ECB
模式解密:echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d ------------------------- hello
CBC
模式加密:echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64 ------------------------- alvrvb3Gz88=
CBC
模式解密:echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d ------------------------- hello
案例2:
使用
AES
加解密
ECB
模式加密:echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64 ------------------------- d1QG4T2tivoi0Kiu3NEmZQ==
ECB
模式解密:echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d ------------------------- hello
CBC
模式加密:echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64 ------------------------- u3W/N816uzFpcg6pZ+kbdg==
CBC
模式解密:echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d ------------------------- hello
代码演示
案例1:
使用
AES
的ECB
模式加密使用
EncryptionTools
库,提供以下方法:#import <Foundation/Foundation.h> #import <CommonCrypto/CommonCrypto.h> @interface EncryptionTools : NSObject + (instancetype)sharedEncryptionTools; /** @constant kCCAlgorithmAES 高级加密标准,128位(默认) @constant kCCAlgorithmDES 数据加密标准 */ @property (nonatomic, assign) uint32_t algorithm; //加密字符串并返回base64编码字符串 - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv; //解密字符串 - (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv; @end
打开
ViewController.m
文件,写入以下代码:#import "ViewController.h" #import "EncryptionTools.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES; NSString *strKey = @"abc"; NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:strKey iv:nil]; NSLog(@"加密:%@",strEncrypt); NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:nil]; NSLog(@"解密:%@",strDecrypt); } @end
运行项目,输出以下内容:
加密:d1QG4T2tivoi0Kiu3NEmZQ== 解密:hello
案例2:
使用
AES
的CBC
模式加密打开
ViewController.m
文件,写入以下代码:#import "ViewController.h" #import "EncryptionTools.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES; NSString *strKey = @"abc"; uint8_t iv[8] = {1,2,3,4,5,6,7,8}; NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)]; NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:strKey iv:ivData]; NSLog(@"加密:%@",strEncrypt); NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:ivData]; NSLog(@"解密:%@",strDecrypt); } @end
运行项目,输出以下内容:
加密:u3W/N816uzFpcg6pZ+kbdg== 解密:hello
CCCrypt函数
在
EncryptionTools
库中,加解密使用的核心代码,都是系统提供的CCCrypt
函数CCCryptorStatus CCCrypt( CCOperation op, /* kCCEncrypt, etc. */ CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */ CCOptions options, /* kCCOptionPKCS7Padding, etc. */ const void *key, size_t keyLength, const void *iv, /* optional initialization vector */ const void *dataIn, /* optional per op and alg */ size_t dataInLength, void *dataOut, /* data RETURNED here */ size_t dataOutAvailable, size_t *dataOutMoved) API_AVAILABLE(macos(10.4), ios(2.0));
op
:kCCEncrypt
加密、kCCDecrypt
解密alg
:加解密使用的算法标准options
:加密选项ECB/CBC
key
:key
的内存地址keyLength
:key
的长度iv
:初始化向量,固定长度8字节
dataIn
:加密数据的内存地址dataInLength
:加密的数据长度dataOut
:密文的内存地址dataOutAvailable
:密文需要的可用空间大小,数据缓冲区的大小(字节)dataOutMoved
:操作成功之后,被写入dataOut
的字节长度。如果由于提供的缓冲区空间不足而返回kCCBufferTooSmall
,则在这里返回所需的缓冲区空间
CCAlgorithm alg
:加解密使用的算法标准enum { kCCAlgorithmAES128 = 0, /* Deprecated, name phased out due to ambiguity with key size */ kCCAlgorithmAES = 0, kCCAlgorithmDES, kCCAlgorithm3DES, kCCAlgorithmCAST, kCCAlgorithmRC4, kCCAlgorithmRC2, kCCAlgorithmBlowfish }; typedef uint32_t CCAlgorithm;
CCOptions options
:加密选项ECB/CBC
enum { /* options for block ciphers */ kCCOptionPKCS7Padding = 0x0001, kCCOptionECBMode = 0x0002 /* stream ciphers currently have no options */ }; typedef uint32_t CCOptions;
kCCOptionPKCS7Padding | kCCOptionECBMode
:ECB
模式kCCOptionPKCS7Padding
:CBC
模式
keyLength
:key
的长度enum { kCCKeySizeAES128 = 16, kCCKeySizeAES192 = 24, kCCKeySizeAES256 = 32, kCCKeySizeDES = 8, kCCKeySize3DES = 24, kCCKeySizeMinCAST = 5, kCCKeySizeMaxCAST = 16, kCCKeySizeMinRC4 = 1, kCCKeySizeMaxRC4 = 512, kCCKeySizeMinRC2 = 1, kCCKeySizeMaxRC2 = 128, kCCKeySizeMinBlowfish = 8, kCCKeySizeMaxBlowfish = 56, };
设置初始化向量
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; }
- 初始化向量
iv
,CBC
模式下需要
blockSize
:支持的算法的块大小(字节)enum { /* AES */ kCCBlockSizeAES128 = 16, /* DES */ kCCBlockSizeDES = 8, /* 3DES */ kCCBlockSize3DES = 8, /* CAST */ kCCBlockSizeCAST = 8, kCCBlockSizeRC2 = 8, kCCBlockSizeBlowfish = 8, };
使用
CCCrypt
函数的安全隐患
App
中数据加密,作为攻击者,最先尝试的解密方式,就是对CCCrypt
函数设置符号断点选择
Symbolic Breakpoint...
输入
CCCrypt
真机运行项目,来到
CCCrypt
函数
在
lldb
中,获取加密数据的内存地址register read x6 ------------------------- x6 = 0x0000000282668ef0
读取地址中的数据,转为
char *
输出po (char *)0x0000000282668ef0 ------------------------- hello
上述案例中,通过符号断点,将传递
CCCrypt
函数的原文参数轻松截获所以,如果开发团队有能力,最好自己实现加解密方法,替代系统的
CCCrypt
函数如果无法避免
CCCrypt
函数的使用,尽量不要直接传递原文和key
,建议对其进行异或加密
,然后再调用CCCrypt
函数
案例1:
异或加密
打开
ViewController.m
文件,写入以下代码:#import "ViewController.h" #import "EncryptionTools.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES; NSString *strKey = @"abc"; uint8_t iv[8] = {1,2,3,4,5,6,7,8}; NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)]; NSString *strXOR = [self stringXOR:@"hello"]; NSLog(@"XOR:%@",strXOR); NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:strXOR keyString:strKey iv:ivData]; NSLog(@"加密:%@",strEncrypt); NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:ivData]; NSLog(@"解密:%@",strDecrypt); NSString *strHello = [self stringXOR:strDecrypt]; NSLog(@"原文:%@",strHello); } - (NSString *)stringXOR:(NSString *)str { NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; char *dataP = (char *)[data bytes]; for (int i = 0; i < data.length; i++) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsequenced" *dataP = *(++dataP) ^ 1; #pragma clang diagnostic pop } str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return str; } @end
运行项目,输出以下内容:
XOR:hdmmn 加密:CDX04B6XEQu+sf6Iyrot3w== 解密:hdmmn 原文:hello
总结
常用的对称加密算法:
DES
3DES
AES
应用模式:
ECB
:电子密码本模式。每一块数据,独立加密CBC
:密码分组链接模式。每一块数据的加密都依赖上一块数据,有效保证数据的完整性,相对安全
CBC
模式
- 需要使用初始化向量
iv
对数据执行加密。固定长度,8字节
CCCrypt
函数
- 直接使用会有安全隐患