iOS-加密相关

341 阅读16分钟

一. 哈希算法

MD5和SHA都是用于创建唯一密钥以保护数据文件的哈希算法。从黑客的角度来看,SHA比MD5更复杂,更难破解。

常见的哈希算法包括: MD5:全称“Message Digest Algorithm 5”,译为“消息摘要算法第5版” SHA家族:全称“Secure Hash Algorithm”,译为“安全哈希算法” HMAC:全称“Hash-based Message Authentication Code”译为“密钥相关的哈希运算消息认证码”

SHA和MD5都是哈希算法,其中MD5在速度方面是最高效的。 但是,与MD5相比,SHA是安全的算法。两种哈希算法的基础是它们从接收到的消息中生成加密摘要或哈希的能力。

哈希算法的基本功能包括:

  1. 将任意长度的二进制值映射为较短的固定长度的二进制值,这个短的二进制值称为哈希值或消息摘要。
  2. 这个算法具有不可逆性,因为它是单向功能,不存在一个算法能够由哈希值倒算出原始信息。
  3. 输入两个不同的明文永远不会有两个类似的哈希值或消息摘要。对原始信息的任何一点改变都会导致结果的哈希值巨大的不同。

哈希算法使用举例:密码加密、文件校验

  1. 密码加密 比如我有一个网站,用户注册的时候会输入用户名密码,大家都知道如果密码是明文的方式存储在数据库里的话,如果这个数据泄漏或者内部人员作恶的话,会造成信息安全问题。所以通用的做法是把用户输入的密码做MD5或SHA-1的运算,把返回的固定长度的哈希值存储在数据库中。比如用户的密码是”bigcat”,实际存储在数据库中的值是它的SHA-1的值a748bf7fee2289b22d448ed8efde10a68f7d1cf9。因为这两个函数的“不可逆”性,所以任何人拿到这个hash值是无法知道用户的明文密码的。当用户设置密码的时候,在服务器存储密码的哈希值,这样当用户再次登录的时候,如果输入的密码的哈希值和服务器存储的哈希值是一样的,这样就代表用户密码输入正确。

  2. 文件完整性验证 在网上下载大尺寸文件的时候常见到网站同时会提供这个文件的MD5的值,它的作用是用户下载后可以在下载文件基础上计算MD5的值,如果和网站提供的MD5是相同的说明文件在下载过程中没有损坏或者说文件没有被恶意网站修改。

1. MD5

MD5 Message-Digest Algorithm,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。

将数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理。

1996年后被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。

MD5破解和改进

直接使用MD5加密可以被破解网站破解,MD5解密网站:www.cmd5.com

cmd5

现在的MD5已不再是绝对安全,因此,可以对MD5稍作改进,以增加破解的难度。

  1. 先乱序,后加密,就是加盐(Salt):在明文的固定位置插入随机串,然后再进行MD5。
  2. 先加密,后乱序:先对明文进行MD5,然后对加密得到的MD5串的字符进行乱序。

总之宗旨就是:黑客就算攻破了数据库,也无法解密出正确的明文。

举例说明:

#import "ViewController.h"
#import "NSString+Hash.h"

#define Salt @"fsdhjkfhjksdhjkfjhkd546783765"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self digest4:@"123"]; //
    [self digest4:@"abc"];
    [self digest4:@"456"];
}

//直接用MD5加密
- (NSString *)digest:(NSString *)str {
    NSString *anwen = [str md5String];
    NSLog(@"%@ - %@", str, anwen);
    return anwen;
}

//加盐
- (NSString *)digest2:(NSString *)str {
    str = [str stringByAppendingString:Salt];
    
    NSString *anwen = [str md5String];
    NSLog(@"%@ - %@", str, anwen);
    return anwen;
}

//多次MD5
- (NSString *)digest3:(NSString *)str {
    NSString *anwen = [str md5String];
    
    anwen = [anwen md5String];
    
    NSLog(@"%@ - %@", str, anwen);
    return anwen;
}

//先加密, 后乱序
- (NSString *)digest4:(NSString *)str {
    NSString *anwen = [str md5String];
    
    // 注册:  123 ----  2CB962AC59075B964B07152D234B7020
    // 登录: 123 --- 202CB962AC59075B964B07152D234B70
    
    NSString *header = [anwen substringToIndex:2];
    NSString *footer = [anwen substringFromIndex:2];
    anwen = [footer stringByAppendingString:header];
    
    NSLog(@"%@ - %@", str, anwen);
    return anwen;
}
@end

打印:

直接使用MD5加密(去MD5解密网站即可破解)

2019-11-14 17:39:19.756320+0800 加密[1637:136552] 123 - 202cb962ac59075b964b07152d234b70
2019-11-14 17:39:19.756447+0800 加密[1637:136552] abc - 900150983cd24fb0d6963f7d28e17f72
2019-11-14 17:39:19.756524+0800 加密[1637:136552] 456 - 250cf8b51c773f3f8dc8b4be867a9a02

使用加盐(通过MD5解密之后,很容易发现规律)

2019-11-14 17:40:45.093899+0800 加密[1677:138250] 123fsdhjkfhjksdhjkfjhkd546783765 - ea4d90423e35126b92565a01c6181517
2019-11-14 17:40:45.094137+0800 加密[1677:138250] abcfsdhjkfhjksdhjkfjhkd546783765 - 09613109a9672ba60c0eb9c456c8b0b2
2019-11-14 17:40:45.094349+0800 加密[1677:138250] 456fsdhjkfhjksdhjkfjhkd546783765 - 9125e7153a18c667e8cfe10cfbcc2baa

多次MD5加密(使用MD5解密之后,发现还是密文,那就接着MD5解密,即可破解)

2019-11-14 17:42:41.410832+0800 加密[1706:140308] 123 - d9b1d7db4cd6e70935368a1efb10e377
2019-11-14 17:42:41.410997+0800 加密[1706:140308] abc - ec0405c5aef93e771cd80e0db180b88b
2019-11-14 17:42:41.411100+0800 加密[1706:140308] 456 - 54a2ec5f4421fa24bfa9bf6461e649a2

先加密,后乱序(破解难度增加)

2019-11-14 17:43:19.845757+0800 加密[1723:140972] 123 - 2cb962ac59075b964b07152d234b7020
2019-11-14 17:43:19.845885+0800 加密[1723:140972] abc - 0150983cd24fb0d6963f7d28e17f7290
2019-11-14 17:43:19.845988+0800 加密[1723:140972] 456 - 0cf8b51c773f3f8dc8b4be867a9a0225

2. SHA家族

安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。 能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。 SHA家族的算法,由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布,是美国的政府标准,其分别是:

  • SHA-0:1993年发布,当时称做安全散列标准(Secure Hash Standard),发布之后很快就被NSA撤回,是SHA-1的前身。
  • SHA-1:1995年发布,SHA-1在许多安全协议中广为使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为使用的散列函数)的后继者。但SHA-1的安全性在2000年以后已经不被大多数的加密场景所接受。 2017年荷兰密码学研究小组CWI和Google正式宣布攻破了SHA-1。
  • SHA-2:2001年发布,包括SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。 虽然至今尚未出现对SHA-2有效的攻击,它的算法跟SHA-1基本上仍然相似;因此有些人开始发展其他替代的散列算法。
  • SHA-3:2015年正式发布,SHA-3并不是要取代SHA-2,因为SHA-2目前并没有出现明显的弱点。 由于对MD5出现成功的破解,以及对SHA-0和SHA-1出现理论上破解的方法,NIST感觉需要一个与之前算法不同的,可替换的加密散列算法,也就是现在的SHA-3。

MD5和SHA1区别

  • MD5简单、速度快、安全性差。
  • SHA1复杂、速度相对较慢、提供可容忍的安全性。

MD5和SHA的消息摘要长度:

  • MD5从任意长度的输入消息中产生相当于128位的消息摘要
  • 根据联邦信息处理标准,有四种安全哈希算法,即SHA-1,SHA-256,SHA-384和SHA-512。这四个函数都是迭代和单向函数,可以压缩长度在2^64 至 2^128之间的消息,以生成大约160位到512位的消息摘要。

安全性:

  • 直接使用MD5加密可以被破解网站破解,尽管它作为最常用的哈希函数之一而受到欢迎,但是对于依赖于冲突抵抗的系统,它并不是最优选的基于安全性的服务。
  • SHA被认为比MD5更安全,它需要大量的位作为输入,并生成较短且更安全的固定大小的输出。当前,有一些SHA1更好的版本已消除了大多数漏洞,例如SHA-256,SHA-384,SHA-512,后缀表示消息摘要的强度级别。

版本:

  • MD5和SHA1之间的主要区别是,MD5是第一个要开发的算法,它具有多个漏洞,入侵者可以利用这些漏洞为消息摘要或哈希创建冲突。因此,SHA1是MD5在功能和安全性方面的增强。从那以后,SHA1的第一个版本中的漏洞已通过后续版本SHA-256和SHA-512消除。

3. HMAC介绍

HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,是1996年提出的一种基于Hash函数和密钥进行消息认证的方法,它可以与任何迭代散列函数捆绑使用。

① 基本功能:

HMAC是一种利用密码学中的散列函数来进行消息认证的一种机制,所能提供的消息认证包括两方面内容:

  1. 消息完整性认证:能够证明消息内容在传送过程没有被修改。
  2. 信源身份认证:因为通信双方共享了认证的密钥,接收方能够认证发送该数据的信源与所宣称的一致,即能够可靠地确认接收的消息与发送的一致。

HMAC是当前许多安全协议所选用的提供认证服务的方式,应用十分广泛,并且经受住了多种形式攻击的考验。

② 算法密钥:

HMAC运算利用hash算法,以一个消息M和一个密钥K作为输入,生成一个定长的消息摘要作为输出。HMAC算法利用已有的Hash函数,关键问题是如何使用密钥。

HMAC的密钥长度可以是任意大小,如果小于n(hash输出值的大小),那么将会消弱算法安全的强度。建议使用长度大于n的密钥,但是采用长度大的密钥并不意味着增强了函数的安全性。密钥应该是随机选取的,可以采用一种强伪随机发生器,并且密钥需要周期性更新,这样可以减少散列函数弱密钥的危险性以及已经暴露密钥所带来的破坏。

③ 安全性:

HMAC算法更象是一种加密算法,它引入了密钥,其安全性已经不完全依赖于所使用的Hash算法,安全性主要有以下几点保证。

  1. 使用的密钥是双方事先约定的,第三方不可能知道。作为非法截获信息的第三方,能够得到的信息只有作为“挑战”的随机数和作为“响应”的HMAC 结果,无法根据这两个数据推算出密钥。由于不知道密钥,所以无法仿造出一致的响应。
  2. HMAC与一般的加密重要的区别在于它具有“瞬时"性,即认证只在当时有效,而加密算法被破解后,以前的加密结果就可能被解密。

HMAC的安全性依赖于散列函数H的密码学属性:①抗碰撞属性;②当应用于一个单独的消息分组时H的压缩函数的消息认证属性。

④ 典型应用:

HMAC的一个典型应用是用在“挑战/响应”(Challenge/Response)身份认证中,认证流程如下:

  1. 先由客户端向服务器发出一个验证请求。
  2. 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战)。
  3. 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
  4. 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户。

上面提到的MD5、SHA散列函数、HMAC散列函数、文件散列函数相关的代码在Demo:散列函数

二. Base64编码

iOS的base64编码解码有两种方式,第一种是使用GTMBase64第三方库,这种方式不推荐,因为iOS7.0以后,Foundation框架的NSData自带base64编码解码的方法,直接调用即可。

NSData的base64编码解码API有两个,一个是data -> string:

//base64编码
NSString *base64String = [data base64EncodedStringWithOptions:0];
//base64解码
NSData *baseData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];

一个是data -> data:

//base64编码
NSData *base64Data = [data base64EncodedDataWithOptions:0];
//base64解码
NSData *baseData = [[NSData alloc] initWithBase64EncodedData:baseData options:0];

我们使用第一个就好,给NSString添加分类,命名Base64,代码如下:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSString (Base64)

// Base64编码方法
- (NSString *)base64EncodingString;

// Base64解码方法
- (NSString *)base64DecodingString;

@end
#import "NSString+Base64.h"

@implementation NSString (Base64)

// Base64编码方法
- (NSString *)base64EncodingString {
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    return [data base64EncodedStringWithOptions:0];;
}

// Base64解码方法
- (NSString *)base64DecodingString {
    NSData *data = [[NSData alloc]initWithBase64EncodedString:self options:0];
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

@end

测试代码如下:

NSString *string = @"abcdefg";              // 常规字符串
NSString *base64String = @"YWJjZGVmZw==";   // Base64字符串

NSLog(@"Base64编码方法:%@", [string base64EncodingString]);
NSLog(@"Base64解码方法:%@", [base64String base64DecodingString]);

打印:

Base64Demo[3997:87408] Base64编码方法二:YWJjZGVmZw==
Base64Demo[3997:87408] Base64解码方法二:abcdefg

可以发现,编码解码成功。

三. 加密

1. 对称加密

全称symmetric-key encryption,其中常见的算法包括了 AESDES、3DES、RC4 等。

  • 对称加密指的是可以使用同一个密钥对内容进行加密和解密,相比非对称加密,它的特点是加/解密速度快,并且加密的内容长度几乎没有限制,缺点是一旦密钥泄露,别人也能解密数据。

2. 非对称加密

全称asymmetric/public-key encryption,常见的加密算法有 RSA、DSA、ECC 等。

  • 非对称加密有两个密钥,分别为公钥和私钥,其中公钥公开给所有人(客户端),私钥永远只能自己(服务端)知道。
  • 使用公钥加密的信息只能使用私钥解密,用来传输需要保密的信息,因为全世界只有知道对应私钥的人才可以解密。
  • 使用私钥加密只能使用公钥解密,用来作数字签名,因为公钥对所有人公开的,可以用来确认这个信息是否是从私钥的拥有者发出的。

3. 国密

对于开发人员,开发中加解密是经常用到的,常见的密码算法 MD5、SHA、AES、DES,RSA 等等,这些无一例外都是国外的加密算法。基于安全和宏观战略考虑,我国从 2010 年先后推出了 SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、ZUC(祖冲之密码算法)等密码算法。

国密全家桶

国密算法中,SM1、SM4、SM7、ZUC 是对称算法;SM2、SM9是非对称算法;SM3是哈希算法。其中 SM1 和 SM7 分组密码算法不公开,SM1 主要用于加密芯片等重要领域,例如 智能 IC 卡,加密机等;SM7 主要用于常规非接触式 IC 卡,例如门禁卡,工作证等。

算法公开类似主要用途
SM1AES智能IC卡、加密卡,加密机等。
SM2RSA重要信息的加解密,如密码。
SM3SHA密码应用中的数字签名和验证。
SM4AES分组算法用于无线局域网产品。
SM7AES校园一卡通,门禁卡,工作证等。
SM9SSL基于身份的密码,用于验证身份。
ZUCAES4G 网络中的国际标准密码算法。

对于我们来说,只需要记住SM2相当于RSA,SM3相当于SHA,SM4相当于AES,就行了。

国密的 Objective-C 封装

OpenSSL实现了 SM2/SM3/SM4 密码算法,但没有注释说明,且纯 C 的 API 用起来不方便。所以,GMObjC对 SM2/SM3/SM4 进行了 Objective-C 封装,方便在 iOS 端使用。

原文博客地址:iOS 使用 SM2 SM4 加解密,SM2 签名验签及 SM3 签名

补充:什么是OpenSSL?

  • OpenSSL是一个开放源代码的软件库包。
  • 应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。
  • OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库、应用程序以及密码算法库。