Straw's B1og.

ios学习篇(3)-ios常见加密

字数统计: 1.5k阅读时长: 7 min
2024/07/04

ios常见加密

前言

​ 在学习篇(1)中有提及过CCCrypt,最近在学习登录加密算法的时候发现ios的加密大部分都是调用函数库的,现在来总结一下现在遇到的比较多见的加密。

CC_MD5

​ 最简单也是最常用的

1
2
3
4
5
6
7
8
9
10
11
12
-(NSString *)stringWithMD5{
const char *cStr = [self UTF8String];
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call

NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];

for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];

return output;
}

CC_SHA1…

​ 与MD5一样也比较多见

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-(NSString *)stringWithSha1Encode{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];

NSData *data = [NSData dataWithBytes:cstr length:self.length];
//使用对应的CC_SHA1,CC_SHA256,CC_SHA384,CC_SHA512的长度分别是20,32,48,64
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
//使用对应的CC_SHA256,CC_SHA384,CC_SHA512
CC_SHA1(data.bytes, (CC_LONG)data.length, digest);

NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];

return output;
}

​ 两个加密所用到的参数也只有三个,原文,原文长度,密文,非常的好认

CCCrypt

​ 这个就比较难了,包含了许多分组对称加密

1
2
3
4
5
6
7
8
9
10
11
12
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)

CCOperation op

​ 很简单,加密kCCEncrypt,解密kCCDecrypt

CCAlgorithm alg

​ 选择加密算法

1
2
3
4
5
6
7
8
9
10
11
enum {
kCCAlgorithmAES128 = 0,
kCCAlgorithmAES = 0,
kCCAlgorithmDES,
kCCAlgorithm3DES,
kCCAlgorithmCAST,
kCCAlgorithmRC4,
kCCAlgorithmRC2,
kCCAlgorithmBlowfish
};
typedef uint32_t CCAlgorithm;

CCOptions options

​ 选择是否填充,默认是CBC模式

1
2
3
4
5
6
7
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;

const void *key

​ 传入的密钥,经过从cstring utf8转成字节类型

1
2
3
char keyPtr[kCCKeySizeAES256 + 1];//选择aes256加密,所以key长度应该是kCCKeySizeAES256,32位
bzero(keyPtr, sizeof(keyPtr));//清零
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];//秘钥key转成cString

​ 需要注意的是如果这里申请的空间不够,加解密会出现问题的,传入的密钥过长,会自动截取,密钥长度不够,自动补全

size_t keyLength

​ 这里是真正决定密钥长度的地方,可选列表是下面这些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,
};

const void *iv

​ 偏移

const void *dataIn,size_t dataInLength

​ 明文和明文长度

void *dataOut,size_t dataOutAvailable,size_t *dataOutMoved

​ 密文,密文块,被写入密文的密文块长度

SecKeyEncrypt

​ 用在RSA加密中会比较多

1
SecKeyEncrypt(key, kSecPaddingPKCS1,(const uint8_t *)[buffer bytes],[buffer length],cipherBuffer,&cipherBufferSize);

总结

​ 主要了解了加密函数,以及对应的参数,我们就可以使用frida-trace去跟踪app登录时的调用函数,使用修改frida的handlers脚本,来获取明文密文,来分析加密过程。

例子-喜某某雅的登录加密算法

​ 首先我们使用Charles对手机进行代理抓包,抓取登录时的发包与响应

抓包

​ 然后我们尝试使用修改追踪脚本的方式,查找我们的输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* Auto-generated by Frida. Please modify to match the signature of SecKeyEncrypt.
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/

{
/**
* Called synchronously when about to call SecKeyEncrypt.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
log('SecKeyEncrypt()');
log('SecKeyEncrypt() key:' + hexdump(args[0]));
log('SecKeyEncrypt() padding:' + (args[1]).toInt32());
log('SecKeyEncrypt() plainText:' + (args[2]).readCString());
log('SecKeyEncrypt() plainTextSize:' + (args[3]).toInt32());
this.args4=args[4];
this.args5=args[5];
},

/**
* Called synchronously when about to return from SecKeyEncrypt.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
log('SecKeyEncrypt() cipherText:'+hexdump(this.args4));
log('SecKeyEncrypt() cipherTextSize:'+(this.args5).readInt());
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
* Auto-generated by Frida. Please modify to match the signature of CC_SHA1.
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/

{
/**
* Called synchronously when about to call CC_SHA1.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
log('CC_SHA1() onEnter:' + args[0].readCString(args[1].toInt32()));
this.args2 =args[2];
},

/**
* Called synchronously when about to return from CC_SHA1.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
log('CC_SHA1() onLeave:' + hexdump(this.args2,{length:20}));
}
}

利用frida-trace -U -i CCCrypt -i CC_MD5 -i CC_SHA1 -i SecKeyEncrypt -f com.gemd.iting跟踪,登录账号

验证

我们可以轻松看出我们输入的账号(手机号)与密码数据先进行了一次RSA加密,然后再进行了一次SHA1加密,

然后发现SHA1的明文是好多进行了RSA加密后的数据,包括账号密码,SHA1的返回值就是我们的signature签名,而RSA加密的数据以base64的方式显示出来

base64

(该图为前一次发包,数据不一样,只提供加密逻辑)

至此我们只要获取RSA的密钥即可破解登录检验的加密算法

已老实

参考链接:

https://www.jianshu.com/p/93466b31f675

iOS常用加密之RSA加密解密 - Francis01 - 博客园 (cnblogs.com)

CATALOG
  1. 1. ios常见加密
    1. 1.1. 前言
    2. 1.2. CC_MD5
    3. 1.3. CC_SHA1…
    4. 1.4. CCCrypt
      1. 1.4.1. CCOperation op
      2. 1.4.2. CCAlgorithm alg
      3. 1.4.3. CCOptions options
      4. 1.4.4. const void *key
      5. 1.4.5. size_t keyLength
      6. 1.4.6. const void *iv
      7. 1.4.7. const void *dataIn,size_t dataInLength
      8. 1.4.8. void *dataOut,size_t dataOutAvailable,size_t *dataOutMoved
    5. 1.5. SecKeyEncrypt
    6. 1.6. 总结
    7. 1.7. 例子-喜某某雅的登录加密算法