iOS 逆向开发 文章汇总
目录
- 一、HASH概述
- 二、用户密码加密
- 三、数字签名
- 四、总结
一、HASH概述
Hash,一般翻译做“散列
”,也有直接音译为“哈希
”的,就是把任意长度
的输入通过散列算法变换成固定长度
的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会
散列成相同的输出(Hash碰撞
),所以不可能
从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
1.1 常见的Hash算法
- MD5
- SHA1、SHA265、SHA512
1.2 Hash的特点
- 算法是公开的
- 对相同数据运算,得到的结果是一样的
- 对不同数据运算,如MD5得到的结果默认是128位(2^128),
32个字符(16进制标识:16^32)
。 - Hash结果
无法逆运算
,因此Hash不能作为加密算法。 - 信息摘要,信息“
指纹
”,是用来做数据识别的。
1.3 Hash用途
- 用户密码的加密
- 搜索引擎:关键词Hash相加
- 版权:网站保存原文件的Hash值,供用户下载的文件加了盐,Hash不一样。网盘保存的文件通过Hash值去重(同时也要防止Hash碰撞)。文件修改文件名和文件后缀不会改变Hash值(压缩/Base64可以改变Hash值)。
- 数字签名
二、用户密码加密
通过运用HASH算法,给用户的密码进行加密。
用户密码加密方式
- 直接使用MD5
- MD5加盐
- HMAC加密方案
- 添点东西
思考:直接使用RSA加密传输用户密码的优缺点?
- 优点:在网络传输泄露的风险低
- 缺点:服务端收到加密后的密码解密明文保存到数据库中非常不安全。
- 如果服务端不解密保存到数据库的就是密文,那么黑客直接抓包拿到请求中的密文也能绕过RSA解密。
- RSA中的公钥和私钥对程序员是公开的,程序员的泄露也是很大的风险。
HASH加密用户密码
HASH加密用户密码后服务器中就不会出现明文密码了
#import "NSString+Hash.h" --->文末
NSString *pwd = @"123456";
pwd = pwd.md5String;
NSLog(@"现在的密码是:%@",pwd);//e10adc3949ba59abbe56e057f20f883e
存在的问题:通过查询HASH值可以查询出很多明文。查询网址
改进:加盐
/* 加盐 */
static NSString *salt = @"LKSJDFLKJ&^&@@";
NSString *pwd = @"123456";
pwd = [pwd stringByAppendingString:salt].md5String;
NSLog(@"现在的密码是:%@",pwd);//2359298f49af5695a4b846e95bdea467
存在的问题:固定盐对开发者的依赖很大
HAMC:服务器发盐
NSString *pwd = @"123456";
//HMAC 加密方式!! KEY 由服务器提供。 给定hmac一个Key,对明文进行两次散列
//一个账号,一个KEY!!
pwd = [pwd hmacMD5StringWithKey:@"differ"];
存在的问题:可以直接使用Hash值进行登录
HAMC+时间戳
三、数字签名
为什么用签名这个词.因为老外喜欢用支票,支票上面的签名能够证明这玩意是你的.那么数字签名顾名思义,就是用于鉴别数字信息的方法
- 为了防止传输中的数据被篡改需要将
数据
和数据的Hash值
一起传递给客户端 - 为了防止
数据
和数据的Hash值
同时被篡改,数据的Hash值
通过RSA
再加密一次
四、总结
- RSA终端代码、RSA代码演示。
- RSA的特点
- RSA的安全系数非常高(因为整个业务逻辑非常安全)
- 加密效率非常低(不能做大数据加密)
- 用来加密关键数据!(对称加密的Key,数字签名中的Hash值)
- HASH
- 不可逆运算
- 相同的数据结果相同
- 不同的数据长度相同
- 一般用于做数据的识别(密码、版权、百度云数据识别)
- 密码加密
- HMAC (比较好的方案)
- HASH+时间戳。这样的方式,每次加密结果不一样(受时间的影响比较大)
- 数字签名(重点! ! )
- 算法: RSA + HASH
- 目的:验证数据的完整性,不被篡改!
- 逻辑:1.将原始数据进行HASH;2.使用RSA加密HASH值(这部分数据就是原始数据的签名信息)3.将原始数据+数字签名 一起打包发送
NSString+Hash.h
#import
@interface NSString (Hash)
#pragma mark - 散列函数
/**
* 计算MD5散列结果
*
* 终端测试命令:
* @code
* md5 -s "string"
* @endcode
*
* 提示:随着 MD5 碰撞生成器的出现,MD5 算法不应被用于任何软件完整性检查或代码签名的用途。
*
* @return 32个字符的MD5散列字符串
*/
- (NSString *)md5String;
/**
* 计算SHA1散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha1
* @endcode
*
* @return 40个字符的SHA1散列字符串
*/
- (NSString *)sha1String;
/**
* 计算SHA256散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha256
* @endcode
*
* @return 64个字符的SHA256散列字符串
*/
- (NSString *)sha256String;
/**
* 计算SHA 512散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha512
* @endcode
*
* @return 128个字符的SHA 512散列字符串
*/
- (NSString *)sha512String;
#pragma mark - HMAC 散列函数
/**
* 计算HMAC MD5散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl dgst -md5 -hmac "key"
* @endcode
*
* @return 32个字符的HMAC MD5散列字符串
*/
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
/**
* 计算HMAC SHA1散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha1 -hmac "key"
* @endcode
*
* @return 40个字符的HMAC SHA1散列字符串
*/
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
/**
* 计算HMAC SHA256散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha256 -hmac "key"
* @endcode
*
* @return 64个字符的HMAC SHA256散列字符串
*/
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
/**
* 计算HMAC SHA512散列结果
*
* 终端测试命令:
* @code
* echo -n "string" | openssl sha512 -hmac "key"
* @endcode
*
* @return 128个字符的HMAC SHA512散列字符串
*/
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
#pragma mark - 文件散列函数
/**
* 计算文件的MD5散列结果
*
* 终端测试命令:
* @code
* md5 file.dat
* @endcode
*
* @return 32个字符的MD5散列字符串
*/
- (NSString *)fileMD5Hash;
/**
* 计算文件的SHA1散列结果
*
* 终端测试命令:
* @code
* openssl sha1 file.dat
* @endcode
*
* @return 40个字符的SHA1散列字符串
*/
- (NSString *)fileSHA1Hash;
/**
* 计算文件的SHA256散列结果
*
* 终端测试命令:
* @code
* openssl sha256 file.dat
* @endcode
*
* @return 64个字符的SHA256散列字符串
*/
- (NSString *)fileSHA256Hash;
/**
* 计算文件的SHA512散列结果
*
* 终端测试命令:
* @code
* openssl sha512 file.dat
* @endcode
*
* @return 128个字符的SHA512散列字符串
*/
- (NSString *)fileSHA512Hash;
@end
NSString+Hash.m
#import "NSString+Hash.h"
#import
@implementation NSString (Hash)
#pragma mark - 散列函数
- (NSString *)md5String {
const char *str = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)sha1String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)sha256String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)sha512String {
const char *str = self.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(str, (CC_LONG)strlen(str), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - HMAC 散列函数
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - 文件散列函数
#define FileHashDefaultChunkSizeForReadingData 4096
- (NSString *)fileMD5Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_MD5_CTX hashCtx;
CC_MD5_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)fileSHA1Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA1_CTX hashCtx;
CC_SHA1_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)fileSHA256Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA256_CTX hashCtx;
CC_SHA256_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
- (NSString *)fileSHA512Hash {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
if (fp == nil) {
return nil;
}
CC_SHA512_CTX hashCtx;
CC_SHA512_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark - 助手方法
/**
* 返回二进制 Bytes 流的字符串表示形式
*
* @param bytes 二进制 Bytes 数组
* @param length 数组长度
*
* @return 字符串表示形式
*/
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < length; i++) {
[strM appendFormat:@"%02x", bytes[i]];
}
return [strM copy];
}
@end