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

2021-05-01  本文已影响0人  Style_月月

iOS 底层原理 + 逆向 文章汇总
注:大家可以关-注 Wei-Xin 公-众-号 :Style月月专栏

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

OpenSSL终端演示

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

加密

解密

1、DES + ECB

加密

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

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


二进制查看

2、DES + CBC

注:剩余的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%

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

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

有以下的改进建议

总结

上一篇 下一篇

猜你喜欢

热点阅读