草庐IT

iOS逆向之对称算法(下)

iOS是大鑫呀 2023-03-28 原文
本文主要是对称算法的终端演示+代码演示



OpenSSL终端演示

下面主要采用DES、AES和 ECB、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


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

000000000000 111111111111 222222222222 880000000000 111111111111 222222222222 000000000000 ......查看此时的加密后密文二进制,与上面进行对比


  • 变化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是链式加密)


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

代码演示

同样是通过DES、AES和 ECB、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对比,加密强度不一样


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

  • 运行程序


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


作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130595548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)

有以下的改进建议

  • 1、在系统函数之上做一层封装,例如 使用按位异或(最简单的封装)

    • 加密:传入string时,做一次按位异或运算

    • 解密:先解密,再按位异或

  • 2、方法名混淆 - 即方法名不变,但打包上架后进行了一系列的变化

总结

  • 对称加密在iOS中使用的是系统的CCCrypt,有11个参数

  • 直接使用系统的CCCrypt是存在明文泄漏的安全隐患的,所以需要在系统函数之上在做一些操作,来保证明文的安全性


有关iOS逆向之对称算法(下)的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  6. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  7. ruby - 在 Ruby 中实现 Luhn 算法 - 2

    我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s

  8. Ruby 斐波那契算法 - 2

    下面是我写的一个计算斐波那契数列中的值的方法:deffib(n)ifn==0return0endifn==1return1endifn>=2returnfib(n-1)+(fib(n-2))endend它工作到n=14,但在那之后我收到一条消息说程序响应时间太长(我正在使用repl.it)。有人知道为什么会这样吗? 最佳答案 Naivefibonacci进行了大量的重复计算-在fib(14)fib(4)中计算了很多次。您可以将内存添加到您的算法中以使其更快:deffib(n,memo={})ifn==0||n==1returnnen

  9. ruby - 为 IO::popen 拯救 "command not found" - 2

    当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

  10. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

    当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

随机推荐