前言
本篇文章讲解密码算法中的对称加密,也是很常用的一个重要算法策略,希望大家掌握!
一、对称加密
对称加密 👉 明文通过密钥加密得到密文,密文通过密钥解密得到明文。
1.1 常见算法
常用的对称加密算法有👇
DES👉 数据加密标准(用得少,因为强度不够)。3DES👉 使用3个密钥,对相同的数据执行3次加密,强度增强。是通过数量级来增加强度,有3个密钥难保管,没有大量使用。AES👉 高级密码标准。苹果的钥匙串访问就是使用AES。
1.2 应用模式
对称加密算法有2种应用模式:
ECB(Electronic Code Book):电子密码本模式。CBC(Cipher Block Chaining):密码分组链接模式。
1.2.1 ECB
- 最基本的加密模式,也就是通常理解的加密,
相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。 独立加密,独立解密,一块丢失不影响其他块,但是如果有一块被破解其他也一样被破解了。
加密过程如下图👇
上图中红色是加密的,蓝色是未加密的。红色与蓝色互不影响。
1.2.2 CBC
使用一个密钥和一个初始化向量[IV]对数据执行加密。
- 明文被加密前 要与 前面的密文 进行
异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。 CBC加密后的密文是上下文相关的,明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。CBC可以有效的保证密文的完整性,如果一个数据块在传递是丢失或改变,后面的数据将无法正常解密。
总之,CBC模式下,加密和解密,都是后面的数据依赖前面的数据,这样,即使一块被破解其他块不一定被破解。如下图👇
二、终端演示
2.1 ECB演示
首先创建一个文本文件,写入
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
然后加密👇
//openssl默认会加盐
openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out message.bin
xxd表示是二进制格式查看
接着修改内容👇
0000000000
1111111111
8822222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
再次加密查看👇
与第一次加密的相比,发现只有红框处的有变动,共16字节,其他数据完全相同。
那么问题来了,ECB模式加密算法下,分块变动的最小数据是多少呢?
- 只改
一个数字看结果👇
0000000000
1111111111
8222222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
这次变动4个字节。
- 只修改
一个二进制位👇
1000000000
1111111111
2222222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
经过这一些列的变动,可见,是以8字节为单位进行加密的。只影响修改的数据,前后都不影响。
2.2 CBC演示
加密命令👇 openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt -in message.txt -out message.bin 和
ECB一样,首先对原始文本加密👇
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
修改文本再加密👇
0000000000
1111111111
8822222222
0000000000
1111111111
2222222222
0000000000
1111111111
2222222222
2.3 其它命令
2.3.1 DES
DES算法下的ECB模式
// 加密
echo -n LGPerson | openssl enc -des-ecb -K 616263 -nosalt | base64
// 结果
n1dRLbUQF6GZBAZUCi5cXQ==
// 解密
echo -n n1dRLbUQF6GZBAZUCi5cXQ== | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
// 结果
LGPerson%
DES算法下的CBC模式
// 加密
echo -n LGPerson | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
// 结果
K5OLACWULS09wjOhrrXlLg==
// 解密
echo -n K5OLACWULS09wjOhrrXlLg== | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
// 结果
LGPerson%
2.3.2 AES
AES算法下的ECB模式
// 加密
echo -n LGPerson | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
// 结果
kwTnmdXzPxV+fAD8Sh3Dkg==
// 解密
echo -n kwTnmdXzPxV+fAD8Sh3Dkg== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
// 结果
LGPerson%
AES算法下的CBC模式
// 加密
echo -n LGPerson | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
// 结果
7f4sishVR9UeNiqq1FrQXQ==
// 解密
echo -n 7f4sishVR9UeNiqq1FrQXQ== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
// 结果
LGPerson%
⚠️注意:不论是DES算法还是AES算法,都有以下共同点👇
加密过程是先加密,再base64编码。解密过程是先base64解码,再解密。- 加密和解密都是
enc,通过-d区分是加密还是解密。
2.4 key的转换
可以通过xxd获取key对应的二进制数据👇
上图左侧就是二进制数据,右侧就是地址对应的值。
三、代码演示
iOS通过CommonCrypto库支持。
/*
algorithm 控制AES DES
iv控制 ECB CBC
*/
//key
NSString *key = @"abc";
//iv
uint8_t iv[8] = {1,2,3,4,5,6,7,8};
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
//message
NSString *message = @"LGPerson";
// AES算法
// ECB 加密
NSString *encAES_ECBResult = [[EncryptionTools sharedEncryptionTools] encryptString:message keyString:key iv:nil];
NSLog(@"AES_ECB enc:%@",encAES_ECBResult);
// ECB 解密
NSString *decAES_ECBResult = [[EncryptionTools sharedEncryptionTools] decryptString:encAES_ECBResult keyString:key iv:nil];
NSLog(@"AES_ECB dec:%@",decAES_ECBResult);
// CBC 加密
NSString *encAES_CBCResult = [[EncryptionTools sharedEncryptionTools] encryptString:message keyString:key iv:ivData];
NSLog(@"AES_CBC enc:%@",encAES_CBCResult);
// CBC 解密
NSString *decAES_CBCResult = [[EncryptionTools sharedEncryptionTools] decryptString:encAES_CBCResult keyString:key iv:ivData];
NSLog(@"AES_CBC dec:%@",decAES_CBCResult);
//修改加密为DES
[EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
// ECB 加密
NSString *encDES_ECBResult = [[EncryptionTools sharedEncryptionTools] encryptString:message keyString:key iv:nil];
NSLog(@"DES_ECB enc:%@",encDES_ECBResult);
// ECB 解密
NSString *decDES_ECBResult = [[EncryptionTools sharedEncryptionTools] decryptString:encDES_ECBResult keyString:key iv:nil];
NSLog(@"DES_ECB dec:%@",decDES_ECBResult);
// CBC 加密
NSString *encDES_CBCResult = [[EncryptionTools sharedEncryptionTools] encryptString:message keyString:key iv:ivData];
NSLog(@"DES_CBC enc:%@",encDES_CBCResult);
// CBC 解密
NSString *decDES_CBCResult = [[EncryptionTools sharedEncryptionTools] decryptString:encDES_CBCResult keyString:key iv:ivData];
NSLog(@"DES_CBC dec:%@",decDES_CBCResult);
run👇
示例Demo
四、CCCrypt函数
4.1 CCCrypt介绍
CCCrypt对称加密算法的核心函数(加密/解密),共有11个参数👇
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));
CCOperation👉kCCEncrypt加密,kCCDecrypt解密👇
enum {
kCCEncrypt = 0,
kCCDecrypt,
};
typedef uint32_t CCOperation;
CCAlgorithm👉 加密算法,默认为AES
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👉 加密模式👇- ECB:kCCOptionPKCS7Padding | kCCOptionECBMode
- CBC:kCCOptionPKCS7Padding
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;
key👉 密钥keyLength👉 密钥长度iv👉 iv 初始化向量,ECB 不需要。iv定长所以不需要长度(8字节)。dataIn👉 加密/解密的数据dataInLength👉 加密/解密的数据长度dataOut👉 缓冲区(地址),存放密文/明文dataOutAvailable👉 缓冲区大小dataOutMoved👉 加密/解密结果大小
4.2 CCCrypt安全隐患
如果直接在CCCrypt函数上打符号断点👇
然后读取x6和x7的值就直接拿到了明文数据LGPerson和对应的长度👇
4.3解决方案
那如何解决上面的安全隐患呢?有人就想到了很直接的办法 👉 不使用CCCrypt函数,自定义一套加解密算法。这个当然没问题,是可以的。但是如果仍然要坚持用CCCrypt函数呢?👇
- 在调用
CCCrypt之前对数据做一层加密/转换。比如 👉 可以对明文数据进行按位异或再加密,解密时先解密再按位异或还原。 - 对
OC方法名称进行混淆(可编写脚本进行)。
总结
- 对称加密
明文通过密钥加密得到密文,密文通过密钥解密得到明文- 常见算法 1.
DES2.3DES3.AES - 应用模式
ECB(Electronic Code Book):电子密码本模式。 独立加密,独立解密,块与块之间互不影响。CBC(Cipher Block Chaining):密码分组链接模式。后面的数据依赖前面的数据,即使其中一块被破解,要继续破解其它的很难。- 多一个参数
iv 初始化向量 - CCCrypt函数:直接使用会有安全隐患 👉 按位异或&代码混淆
- 多一个参数