美文网首页
对称加密

对称加密

作者: 浅墨入画 | 来源:发表于2021-05-16 18:24 被阅读0次

一. 对称加密算法介绍

对称加密方式:
  • 明文通过密钥加密得到密文。
  • 密文通过密钥解密得到明文。
常见的对称加密算法
  • DES 数据加密标准(用得少,因为强度不够)
  • 3DES 使用3个密钥,对相同的数据执行3次加密,强度增强
  • AES 高级密码标准。
密码本与对称加密的区别
  • 密码本与对称加密算法流程相似,却是两个不同概念
  • 所有的加密算法都使用到数学原理,密码本却没有用到
对称加密的两种应用模式
  • ECB(Electronic Code Book):电子密码本模式。每一块数据,独立加密,独立解密
对称加密-ECB模式

最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。

  • CBC(Cipher Block Chaining):密码分组链接模式。使用一个密钥和一个初始化向量[IV]对数据执行加密。
对称加密-CBC模式

明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
CBC可以有效的保证密文的完整性,如果一个数据块在传递时丢失或改变,后面的数据将无法正常解密

二. 对称加密终端演示

des-ecb模式加密
$ cd /Users/wn/Documents/资料/加密
$ vi abc.txt
$ cat abc.txt
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
// 使用des-ecb模式加密 -K  表示密钥为616263,即ABC的ascii码,openssl库里面的对称加密默认加盐。msg1.bin表示二进制文件
$ openssl enc -des-ecb -K 616263 -nosalt -in abc.txt -out msg1.bin
// 查看二进制文件
$ xxd msg1.bin
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 4fa0 e610 9da8 9c3f  _...le..O......?

// 修改abc.txt内容如下
$ cat abc.txt
000000000000
111111111111
222222222222
880000000000
111111111111
222222222222
$ openssl enc -des-ecb -K 616263 -nosalt -in abc.txt -out msg2.bin
$ xxd msg2.bin
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 4fa0 e610 9da8 9c3f  _...le..O......?
  • 通过比对上面两次加密的密文二进制文件,发现中间一行的16字节内容不同
    00000020: 09a9 fef3 c8f1 9b92 d1f8 0876 7a80 0184 ...........vz...
    00000020: 1087 3405 8261 0661 69c5 1db2 8613 2255 ..4..a.ai....."U
  • 这验证了des-ecb模式加密,是单个数据独立加密。同时说明des-ecb模式加密,修改两个字符,是以16字节为一个单位进行加密
  • 如果修改1个字符,最小单位是8个字节。所以DES加密过程中,最低是以8字节为一个单位进行加密。
des-cbc模式加密
$ cat abc.txt
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
// -iv :表示向量,616263 :加密的key,换成 ABC 也可以
$ openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt -in abc.txt -out msg3.bin
$ xxd msg3.bin
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 b8a2 de4b 558b a14a  h...V(.....KU..J

// 修改abc.txt内容如下
$ cat abc.txt
000000000000
111111111111
222222222222
880000000000
111111111111
222222222222
$ openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt -in abc.txt -out msg4.bin
$ xxd msg4.bin
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 c1f7 2e3d d16a 6daf  .t.7.R.}...=.jm.
  • 继续比对两次加密的密文二进制文件,发现从00000020: a9b0 f336 ee43 9b58 f026 a63f 685a b53f ...6.C.X.&.?hZ.? 00000020: 6560 8a18 d121 1576 26bb 7811 9ac9 d586 e...!.v&.x.....` 就开始不同了
  • 这验证了des-cbc模式加密,是链式加密

三. 对称加密算法代码演练

在新创建的工程中导入加密工具类EncryptionTools如下

<!--EncryptionTools.h-->
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

/**
 *  终端测试指令
 *
 *  DES(ECB)加密
 *  $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
 *
 *  DES(CBC)加密
 *  $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
 *
 *  AES(ECB)加密
 *  $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
 *
 *  AES(CBC)加密
 *  $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
 *
 *  DES(ECB)解密
 *  $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
 *
 *  DES(CBC)解密
 *  $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
 *
 *  AES(ECB)解密
 *  $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
 *
 *  AES(CBC)解密
 *  $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
 *
 *  提示:
 *      1> 加密过程是先加密,再base64编码
 *      2> 解密过程是先base64解码,再解密
 */
@interface EncryptionTools : NSObject
    
+ (instancetype)sharedEncryptionTools;
    
    /**
     @constant   kCCAlgorithmAES     高级加密标准,128位(默认)
     @constant   kCCAlgorithmDES     数据加密标准
     */
    @property (nonatomic, assign) uint32_t algorithm;
    
    /**
     *  加密字符串并返回base64编码字符串
     *
     *  @param string    要加密的字符串
     *  @param keyString 加密密钥
     *  @param iv        初始化向量(8个字节)
     *
     *  @return 返回加密后的base64编码字符串
     */
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
    
    /**
     *  解密字符串
     *
     *  @param string    加密并base64编码后的字符串
     *  @param keyString 解密密钥
     *  @param iv        初始化向量(8个字节)
     *
     *  @return 返回解密后的字符串
     */
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
@end

<!--EncryptionTools.m-->
#import "EncryptionTools.h"

@interface EncryptionTools()
    @property (nonatomic, assign) int keySize;
    @property (nonatomic, assign) int blockSize;
    @end

@implementation EncryptionTools
    
+ (instancetype)sharedEncryptionTools {
    static EncryptionTools *instance;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        instance.algorithm = kCCAlgorithmAES;
    });
    
    return instance;
}
    
- (void)setAlgorithm:(uint32_t)algorithm {
    _algorithm = algorithm;
    switch (algorithm) {
        case kCCAlgorithmAES:
        self.keySize = kCCKeySizeAES128;
        self.blockSize = kCCBlockSizeAES128;
        break;
        case kCCAlgorithmDES:
        self.keySize = kCCKeySizeDES;
        self.blockSize = kCCBlockSizeDES;
        break;
        default:
        break;
    }
}
    
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    
    // 设置秘钥
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 设置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;
    } else {
        /**
         kCCOptionPKCS7Padding | kCCOptionECBMode  ECB 的模式
         kCCOptionPKCS7Padding                     CBC 的加密
         */
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    }
    
    // 设置输出缓冲区
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 开始加密
    size_t encryptedSize = 0;
    //加密解密都是它 -- CCCrypt
    
    /**
     1.kCCEncrypt 加密/kCCDecrypt解密
     2.加密算法
     3.加密选项  ECB/CBC
     4.KEY 的地址
     5.KEY 的长度
     6.iv 初始化向量
     7.加密的数据(地址)
     8.加密的数据长度
     9.密文的内存地址
     10.密文缓冲区的大小
     11.数据的指针(加密结果大小)
     */
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &encryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
    } else {
        free(buffer);
        NSLog(@"[错误] 加密失败|状态编码: %d", cryptStatus);
    }
    
    return [result base64EncodedStringWithOptions:0];
}
    
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    // 设置秘钥
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 设置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;
    }
    
    // 设置输出缓冲区
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 开始解密
    size_t decryptedSize = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &decryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        // 加密/解密成功,不用释放buffer,因为需要返回出去
        result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    } else {
        // 上面malloc了一块区域,加密/解密失败需要释放掉
        free(buffer);
        NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
    }
    
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
@end

主要是通过系统方法CCCrypt实现,其中涉及11个参数,分别是 1.kCCEncrypt 加密/kCCDecrypt解密 2.加密算法 3.加密选项 ECB/CBC 4.KEY 的地址 5.KEY 的长度 6.iv 初始化向量 7.加密的数据(地址) 8.加密的数据长度 9.密文的内存地址 10.密文缓冲区的大小 11.数据的指针(加密结果大小)
安全隐患:使用系统函数同样有数据泄漏的风险

AES - ECB加密
- (void)testEnc{
    NSString *key = @"abc";
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
    NSLog(@"AES - ECB加密 : %@", encStr);
}

<!--运行结果-->
AES - ECB加密 : d1QG4T2tivoi0Kiu3NEmZQ==

<!--终端命令-->
// 将hello作为参数传递给后面进行一次加密,以base64编码输出
$ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
//与程序运行结果是一样的
d1QG4T2tivoi0Kiu3NEmZQ==

// 使用des-ecb加密方式,强度明显弱于aes-ecb加密
$ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
HQr0Oij2kbo=

// aes-ecb解密,%是字符输出的占位符
$ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
hello%
AES - CBC加密
- (void)testEnc{
    uint8_t iv[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
    NSString *key = @"abc";
    //加密
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:ivData];
    
    //解密
    NSString * decStr = [[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:ivData];
    NSLog(@"AES - CBC加密 : %@", encStr);
    NSLog(@"AES - CBC解密  : %@", decStr);
}
//打印结果
AES - CBC加密  : u3W/N816uzFpcg6pZ+kbdg==
AES - CBC解密  : hello

<!--终端命令-->
$ echo -n hello | openssl enc -aes-128-cbc -K 616263 -iv 0102030405060708 -nosalt | base64
u3W/N816uzFpcg6pZ+kbdg==

$ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D |openssl enc -aes-128-cbc -K 616263 -iv 0102030405060708 -nosalt -d
hello%

注意:如果想知道某一个key的16进制,如上面使用的密钥abc,终端使用的616263,可以把创建一个txt文件内容为abc,终端使用命令xxd test.txt即可查到16进制数据

调试CCCrypt

我们通过断点调试来说明其安全隐患,添加符号断点,真机运行程序

image.png

通过寄存器获取参数,发现hello 是明文,这是非常不安全的

image.png

改进方案

  • 在系统函数之上做一层封装,例如 使用按位异或(最简单的封装,效率高,简单)
    加密:传入string时,做一次按位异或运算
    解密:先解密,再按位异或
  • 方法名混淆 - 即方法名不变,但打包上架后进行了一系列的变化

相关文章

  • https交互流程简述

    https使用到的加密算法 对称加密非对称加密 通过非对称加密,交换对称加密的密钥,之后采用对称加密传输非对称加密...

  • Web开发必须了解的密码学技术

    对称加密与非对称加密 按照密钥的使用形式,加密算法可以分为对称加密和非对称加密(又叫公钥加密)。对称加密在加密和解...

  • 加密算法的应用

    加密算法的应用 [TOC] 加密算法 加密算法主要分为对称加密和非对称加密。 对称加密 对称加密采用了对称密码编码...

  • 学习笔记:HTTPS协议原理

    对称加密和非对称加密 加密分两种,对称加密和非对称加密。对称加密是指加密的双方使用同一个密钥加密和解密数据。非对称...

  • Linux系列五之SSH原理深度解析

    一、对称加密和非对称加密 为了理解SSH,先要介绍两个重要概念:对称加密和非对称加密。 1-1、对称加密 所谓对称...

  • https传输过程

    HTTPS传输过程主要涉及到对称加密和非对称加密两种方式,对称加密用来加密数据内容,非对称加密用来加密对称加密的秘...

  • 加密算法的理解

    加密算法按类型分类: 对称加密、非对称加密、散列算法 对称加密: 加密双方都持有加密算法及密钥 非对称加密: 加密...

  • 加密相关

    加密分为:对称加密和非对称加密。非对称加密的用途:1:加解密,但是速度很慢。2:交换对称加密的密钥,对称加密很快3...

  • 对称加密和非对称加密

    对称加密: 对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥。 非对称加密: 加密...

  • 密码学及iOS签名(一) —— 加密解密

    加密解密类型 对称加密 公钥密码(非对称加密) 对称加密(常见的DES、 3DES、AES) 在对称密码中,加密、...

网友评论

      本文标题:对称加密

      本文链接:https://www.haomeiwen.com/subject/vlwljltx.html