iOS逆向 08:对称算法(下)

简介: iOS逆向 08:对称算法(下)

本文主要是对称算法的终端演示+代码演示


OpenSSL终端演示


下面主要采用DES、AESECB、CBC两两组合的方式进行演示,涉及的终端命令主要有以下一些


加密


  • AES + ECB加密“hello”字符串
  • echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
  • AES + CBC加密“hello”字符串
  • echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64


解密


  • 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、DES + ECB


加密

  • vi abc.txt
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
000000000000
111111111111
222222222222
  • 对称加密(默认会加盐):openssl enc -des-ecb -K 016263 -nosalt -in abc.txt -out msg1.bin


  • enc: 表示加密方式,即对称加密
  • msg1.bin: 二进制文件


  • 查看二进制文件:xxd msg1.bin

image.png

  • 将第二个重复的前两个00,改成88


000000000000
111111111111
222222222222
880000000000
111111111111
222222222222
000000000000
......

查看此时的加密后密文二进制,与上面进行对比


image.png

  • 变化931f 4a54 79bf 730f 4453 2df5 e152 38f1 变成了c7e1 1de2 c778 9df6 4d79 8bec 04ad 08c4。说明修改两个字符,其最小单位16字节
  • 如果修改1个字符,最小单位是8个字节。所以加密过程中,最低是8字节


2、DES + CBC


  • vi abc.txt(内容与1中相同)
  • 加密: openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt -in abc.txt -out msg3.bin
  • 修改一个字符,获取 msg4.bin
  • -iv :向量的表示方式
  • 616263 :加密的key,换成 abc 也是可以的
  • 与ECB模式对比:从第2个开始,其二进制就不同了(CBC是链式加密)

image.png

注:剩余的AES+ECB、AES+CBC请读者自行演练,这里就不在做演示了


代码演示


同样是通过DES、AESECB、CBC两两组合的方式进行演示


1、AES + ECB


- (void)testEnc{
//    AES + ECB 加密
    NSString *key = @"abc";
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
    NSLog(@"AES + ECB : %@", encStr);
}
<!--运行结果-->
AES + ECB : d1QG4T2tivoi0Kiu3NEmZQ==
<!--终端命令-->
$ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
//与程序运行结果是一样的
d1QG4T2tivoi0Kiu3NEmZQ==
$ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D |openssl enc -aes-128-ecb -K 616263 -nosalt -d
hello%
  • echo -n hello 输出hello
  • | :表示输出符
  • 注:des 和 aes对比,加密强度不一样

image.png


2、AES + CBC


- (void)testEnc{
//    2、AES + CBC 加密
    uint8_t iv[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    NSData *data = [NSData dataWithBytes:iv length:sizeof(iv)];
    NSString *key = @"abc";
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:data];
    //解密
    NSString * decStr = [[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:data];
    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%


3、DES + ECB


- (void)testEnc{
//    3、DES + ECB
    [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
    NSString *key = @"abc";
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
    NSLog(@"DES + ECB : %@", encStr);
}
//运行结果
DES + ECB : HQr0Oij2kbo=
<!--终端命令-->
$ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
HQr0Oij2kbo=
$ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
hello%


4、DES + CBC


- (void)testEnc{
//    4、DES + CBC
    [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
    uint8_t iv[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    NSData *data = [NSData dataWithBytes:iv length:sizeof(iv)];
    NSString *key = @"abc";
    NSString *encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:data];
    //解密
    NSString * decStr = [[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:data];
    NSLog(@"AES + CBC : %@", encStr);
    NSLog(@"AES + CBC  : %@", decStr);
}
//运行结果
AES + CBC : alvrvb3Gz88=
AES + CBC  : hello
<!--终端命令-->
$ echo -n hello | openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt | base64
alvrvb3Gz88=
$ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -K 616263 -iv 0102030405060708 -nosalt -d
hello%


加密解密实现


以下是DES、AES的完整对称加解密的代码封装

<!--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
<!--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 加密 / kCCDeccrypt 解密
     - 参数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) {
        result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    } else {
        free(buffer);
        NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
    }
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
@end

主要是通过系统的CCCrypt实现,其中涉及11个参数,分别是

- 参数1:kCCEncrypt 加密 / kCCDeccrypt 解密
 - 参数2:加密算法
 - 参数3:加密选项 ECB / CBC
 - 参数4:KEY的地址
 - 参数5:KEY的长度
 - 参数6:iv初始化向量
 - 参数7:加密的数据
 - 参数8:加密数据的长度
 - 参数9:密文的内存地址
 - 参数10:密文缓冲区的大小
 - 参数11:数据的指针(加密结果大小)

安全隐患:使用系统函数同样有数据泄漏的风险


调试CCCrypt


下面我们通过断点调试来说明其安全隐患


  • 加符号断点CCCrypt
  • 运行程序

image.png

调试CCCrypt-01


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


image.png有以下的改进建议


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


总结


  • 对称加密在iOS中使用的是系统的CCCrypt,有11个参数
  • 直接使用系统的CCCrypt是存在明文泄漏的安全隐患的,所以需要在系统函数之上在做一些操作,来保证明文的安全性


相关文章
|
1月前
|
存储 算法 安全
|
1月前
|
安全 算法 Java
【网络安全】网络防护之旅 - 对称密码加密算法的实现
【网络安全】网络防护之旅 - 对称密码加密算法的实现
85 0
|
1月前
|
算法 前端开发
前端算法-对称二叉树
前端算法-对称二叉树
|
1月前
|
算法 安全 数据安全/隐私保护
对称加密算法与非对称加密算法
对称加密算法与非对称加密算法
|
1月前
|
机器学习/深度学习 人工智能 tengine
极智AI | 量化实现分享三:详解ACIQ对称量化算法实现
大家好,我是极智视界,本文剖析一下ACIQ 对称量化算法实现,以 Tengine 的实现为例。
266 0
|
1月前
|
人工智能 tengine 算法
极智AI | 量化实现分享二:详解KL对称量化算法实现
大家好,我是极智视界,本文剖析一下 KL 对称量化算法实现,以 Tengine 的实现为例。
221 0
|
1月前
|
机器学习/深度学习 存储 tengine
极智AI | 量化实现分享一:详解min-max对称量化算法实现
大家好,我是极智视界,本文剖析一下 min-max 对称量化算法实现,以 Tengine 的实现为例。
385 0
|
1月前
|
算法 程序员
【算法训练-二叉树 四】【对称与翻转】对称二叉树、翻转二叉树
【算法训练-二叉树 四】【对称与翻转】对称二叉树、翻转二叉树
35 0
|
1月前
|
算法 数据处理
【MATLAB】极点对称模态ESMD信号分解算法
【MATLAB】极点对称模态ESMD信号分解算法
89 0
|
7月前
|
算法
代码随想录算法训练营第十四天 | LeetCode 102. 二叉树的层序遍历、LeetCode 226. 翻转二叉树、LeetCode 101. 对称二叉树
代码随想录算法训练营第十四天 | LeetCode 102. 二叉树的层序遍历、LeetCode 226. 翻转二叉树、LeetCode 101. 对称二叉树
40 0