iOS逆向实战--012:对称加密

2021-04-19  本文已影响0人  帅驼驼

对称加密方式:明文通过密钥加密得到密文,密文通过密钥解密得到明文。

定义

需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用

对称性加密也称为密钥加密。所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密

因此加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题

算法

采用单钥密码的加密方法,同一个密钥可以同时用来加密和解密,这种加密方法称为对称加密,也称为单密钥加密

常用的对称加密算法:

  • DES:数据加密标准,速度较快,适用于加密大量数据的场合(用得少,因为强度不够)
  • 3DES:是基于DES,对一块数据用3个不同的密钥进行3次加密,强度更高
  • AES:高级加密标准,是下一代的加密算法标准,速度快,安全级别高,支持128192256512位密钥的加密

算法特征:

  • 加密方和解密方使用同一个密钥
  • 加密解密的速度比较快,适合数据比较长时的使用
  • 密钥传输的过程不安全,且容易被破解,密钥管理也比较麻烦
应用模式

ECBElectronic Code Book):电子密码本模式。每一块数据,独立加密

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

CBCCipher Block Chaining):密码分组链接模式。使用一个密钥和一个初始化向量iv对数据执行加密

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

向量iv的作用

很多加密算法都和几何图形有关

几何图形的变量算法同样具有规律性,但算法的规律结果变幻莫测

例如:一个圆上有无数个点,如果把某一个点视为向量iv,加密结果则会有无数种

所以将几何算法添加到加密算法中,它的破解难度系数变得更大

案例1:

创建file.txt文件,写入以下内容:

000000000000
111111111111
222222222222
000000000000
111111111111
222222222222

使用DESECB模式加密,输出二进制文件msg1.bin

openssl enc -des-ecb -K 616263 -nosalt -in file.txt -out msg1.bin
  • 616263abc16进制ASCII
  • openssl命令,默认随机加盐,通过-nosalt参数,取消该策略

使用xxd msg1.bin命令,以16进制输出二进制文件

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 5f01 6db1 eee3 133b  _...le.._.m....;

打开file.txt文件,将第4行开头的00改为88

000000000000
111111111111
222222222222
880000000000
111111111111
222222222222

使用DESECB模式加密,输出二进制文件msg2.bin

openssl enc -des-ecb -K 616263 -nosalt -in file.txt -out msg2.bin

使用xxd msg2.bin命令,以16进制输出二进制文件

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 5f01 6db1 eee3 133b  _...le.._.m....;

对比msg1.binmsg2.bin二进制内容

  • 只有第3行16字节数据发生变化

案例2:

创建file.txt文件,写入以下内容:

000000000000
111111111111
222222222222
000000000000
111111111111
222222222222

使用DESCBC模式加密,输出二进制文件msg1.bin

openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in file.txt -out msg1.bin
  • iv:向量,必须为8字节数据

使用xxd msg1.bin命令,以16进制输出二进制文件

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 7915 0d78 3b10 f2d1  h...V(..y..x;...

打开file.txt文件,将第4行开头的00改为88

000000000000
111111111111
222222222222
880000000000
111111111111
222222222222

使用DESCBC模式加密,输出二进制文件msg2.bin

openssl enc -des-ecb -iv 0102030405060708 -K 616263 -nosalt -in file.txt -out msg2.bin

使用xxd msg2.bin命令,以16进制输出二进制文件

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 ed84 ebe8 d90c 272a  .t.7.R.}......'*

对比msg1.binmsg2.bin二进制内容

  • 第3行开头到二进制的结尾,全部数据发生变化
优缺点

对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高

对称加密算法的缺点是在数据传送前,发送方和接收方必须商定好秘钥,然后使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的独一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担

终端命令

命令的管道输出顺序:

  • 加密过程是先加密,再Base64编码
  • 解密过程是先Base64解码,再解密

案例1:

使用DES加解密

ECB模式加密:

echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
-------------------------
HQr0Oij2kbo=

ECB模式解密:

echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
-------------------------
hello

CBC模式加密:

echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
-------------------------
alvrvb3Gz88=

CBC模式解密:

echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
-------------------------
hello

案例2:

使用AES加解密

ECB模式加密:

echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
-------------------------
d1QG4T2tivoi0Kiu3NEmZQ==

ECB模式解密:

echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
-------------------------
hello

CBC模式加密:

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

CBC模式解密:

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

案例1:

使用AESECB模式加密

使用EncryptionTools库,提供以下方法:

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

@interface EncryptionTools : NSObject
   
+ (instancetype)sharedEncryptionTools;
   
/**
    @constant   kCCAlgorithmAES     高级加密标准,128位(默认)
    @constant   kCCAlgorithmDES     数据加密标准
*/
@property (nonatomic, assign) uint32_t algorithm;
   
//加密字符串并返回base64编码字符串
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;

//解密字符串
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
   
@end

打开ViewController.m文件,写入以下代码:

#import "ViewController.h"
#import "EncryptionTools.h"

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   
   [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES;

   NSString *strKey = @"abc";
   NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:strKey iv:nil];
   NSLog(@"加密:%@",strEncrypt);
   
   NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:nil];
   NSLog(@"解密:%@",strDecrypt);
}

@end

运行项目,输出以下内容:

加密:d1QG4T2tivoi0Kiu3NEmZQ==
解密:hello

案例2:

使用AESCBC模式加密

打开ViewController.m文件,写入以下代码:

#import "ViewController.h"
#import "EncryptionTools.h"

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   
   [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES;

   NSString *strKey = @"abc";

   uint8_t iv[8] = {1,2,3,4,5,6,7,8};
   NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];

   NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:strKey iv:ivData];
   NSLog(@"加密:%@",strEncrypt);

   NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:ivData];
   NSLog(@"解密:%@",strDecrypt);
}

@end

运行项目,输出以下内容:

加密:u3W/N816uzFpcg6pZ+kbdg==
解密:hello
CCCrypt函数

EncryptionTools库中,加解密使用的核心代码,都是系统提供的CCCrypt函数

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));
  • opkCCEncrypt加密、kCCDecrypt解密
  • alg:加解密使用的算法标准
  • options:加密选项ECB/CBC
  • keykey的内存地址
  • keyLengthkey的长度
  • iv:初始化向量,固定长度8字节
  • dataIn:加密数据的内存地址
  • dataInLength:加密的数据长度
  • dataOut:密文的内存地址
  • dataOutAvailable:密文需要的可用空间大小,数据缓冲区的大小(字节)
  • dataOutMoved:操作成功之后,被写入dataOut的字节长度。如果由于提供的缓冲区空间不足而返回kCCBufferTooSmall,则在这里返回所需的缓冲区空间

CCAlgorithm alg:加解密使用的算法标准

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 options:加密选项ECB/CBC

enum {
   /* options for block ciphers */
   kCCOptionPKCS7Padding   = 0x0001,
   kCCOptionECBMode        = 0x0002
   /* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;
  • kCCOptionPKCS7Padding | kCCOptionECBModeECB模式
  • kCCOptionPKCS7PaddingCBC模式

keyLengthkey的长度

enum {
   kCCKeySizeAES128          = 16,
   kCCKeySizeAES192          = 24,
   kCCKeySizeAES256          = 32,
   kCCKeySizeDES             = 8,
   kCCKeySize3DES            = 24,
   kCCKeySizeMinCAST         = 5,
   kCCKeySizeMaxCAST         = 16,
   kCCKeySizeMinRC4          = 1,
   kCCKeySizeMaxRC4          = 512,
   kCCKeySizeMinRC2          = 1,
   kCCKeySizeMaxRC2          = 128,
   kCCKeySizeMinBlowfish     = 8,
   kCCKeySizeMaxBlowfish     = 56,
};

设置初始化向量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;
   }
  • 初始化向量ivCBC模式下需要

blockSize:支持的算法的块大小(字节)

enum {
   /* AES */
   kCCBlockSizeAES128        = 16,
   /* DES */
   kCCBlockSizeDES           = 8,
   /* 3DES */
   kCCBlockSize3DES          = 8,
   /* CAST */
   kCCBlockSizeCAST          = 8,
   kCCBlockSizeRC2           = 8,
   kCCBlockSizeBlowfish      = 8,
};

使用CCCrypt函数的安全隐患

App中数据加密,作为攻击者,最先尝试的解密方式,就是对CCCrypt函数设置符号断点

选择Symbolic Breakpoint...

输入CCCrypt

真机运行项目,来到CCCrypt函数

lldb中,获取加密数据的内存地址

register read x6
-------------------------
x6 = 0x0000000282668ef0

读取地址中的数据,转为char *输出

po (char *)0x0000000282668ef0
-------------------------
hello

上述案例中,通过符号断点,将传递CCCrypt函数的原文参数轻松截获

所以,如果开发团队有能力,最好自己实现加解密方法,替代系统的CCCrypt函数

如果无法避免CCCrypt函数的使用,尽量不要直接传递原文和key,建议对其进行异或加密,然后再调用CCCrypt函数

案例1:

异或加密

打开ViewController.m文件,写入以下代码:

#import "ViewController.h"
#import "EncryptionTools.h"

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   
   [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmAES;

   NSString *strKey = @"abc";

   uint8_t iv[8] = {1,2,3,4,5,6,7,8};
   NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];

   NSString *strXOR = [self stringXOR:@"hello"];
   NSLog(@"XOR:%@",strXOR);

   NSString *strEncrypt = [[EncryptionTools sharedEncryptionTools] encryptString:strXOR keyString:strKey iv:ivData];
   NSLog(@"加密:%@",strEncrypt);

   NSString *strDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:strEncrypt keyString:strKey iv:ivData];
   NSLog(@"解密:%@",strDecrypt);
   
   NSString *strHello = [self stringXOR:strDecrypt];
   NSLog(@"原文:%@",strHello);
}

- (NSString *)stringXOR:(NSString *)str {
   
   NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

   char *dataP = (char *)[data bytes];
   for (int i = 0; i < data.length; i++) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"
       *dataP = *(++dataP) ^ 1;
#pragma clang diagnostic pop
   }

   str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
   return str;
}

@end

运行项目,输出以下内容:

XOR:hdmmn
加密:CDX04B6XEQu+sf6Iyrot3w==
解密:hdmmn
原文:hello
总结

常用的对称加密算法:

  • DES
  • 3DES
  • AES

应用模式:

  • ECB:电子密码本模式。每一块数据,独立加密
  • CBC:密码分组链接模式。每一块数据的加密都依赖上一块数据,有效保证数据的完整性,相对安全

CBC模式

  • 需要使用初始化向量iv对数据执行加密。固定长度,8字节

CCCrypt函数

  • 直接使用会有安全隐患
上一篇下一篇

猜你喜欢

热点阅读