Swift - 第三方加密库CryptoSwift使用详解2(CRC、MAC、PBKDF2)
三、CRC 校验码计算
CRC 即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。
循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
/*** 计算字节数组的CRC值 ***/ let bytes:Array<UInt8> = [0x01, 0x02, 0x03] let crc1 = bytes.crc16() //41232 let crc2 = bytes.crc32() //1438416925 /*** 计算Data的CRC值 ***/ let data = Data(bytes: [0x01, 0x02, 0x03]) let crc3 = data.crc16() //2 bytes let crc4 = data.crc32() //2 bytes /*** 计算字符串的CRC值 ***/ let crc5 = "hangge.com".crc16() //90e7 let crc6 = "hangge.com".crc32() //7eeb79d1
四、消息认证码(MAC)计算
1,消息认证码(MAC)介绍
- 消息认证码是指在密码学中,通信实体双方使用的一种验证机制,保证消息数据完整性的一种工具。
- 其构造方法由 M.Bellare 提出,安全性依赖于 Hash 函数,故也称带密钥的 Hash 函数。
- 消息认证码是基于密钥和消息摘要所获得的一个值,可用于数据源发认证和完整性校验。
2,计算 HMAC
HMAC(Hashed Message Authentication Code)中文名叫做:散列消息身份验证码。关于它的具体介绍可以参考我之前写的这篇文章:Swift - 如何实现字符串的HMAC_SHA1加密
当时使用的是 iOS SDK 自带的 CommonCrypto 库来实现,如果我们使用 CryptoSwift 的话就更简单了。
当时使用的是 iOS SDK 自带的 CommonCrypto 库来实现,如果我们使用 CryptoSwift 的话就更简单了。
let str = "欢迎访问hangge.com" let key = "hangge" let hmac = try! HMAC(key: key.bytes, variant: .sha1).authenticate(str.bytes) print("原始字符串:\(str)") print("key:\(key)") print("HMAC运算结果:\(hmac.toHexString())")运行结果如下:
(2)除了 SHA1,我们还可以使用其它算法比如 MD5,SHA256 等
try! HMAC(key: key.bytes, variant: .md5).authenticate(str.bytes) try! HMAC(key: key.bytes, variant: .sha1).authenticate(str.bytes) try! HMAC(key: key.bytes, variant: .sha256).authenticate(str.bytes) try! HMAC(key: key.bytes, variant: .sha384).authenticate(str.bytes) try! HMAC(key: key.bytes, variant: .sha512).authenticate(str.bytes)
3,计算 Poly1305
Poly1305 是 Daniel.J.Bernstein 创建的消息认证码,可用于检测消息的完整性和验证消息的真实性,现常在网络安全协议(SSL/TLS)中与 salsa20 或 ChaCha20 流密码结合使用。
Poly1305 消息认证码的输入为 32 字节(256bit)的密钥和任意长度的消息比特流,经过一系列计算生成 16 字节(128bit)的摘要。
使用代码如下,这里我们还是使用一个字符串来生成一个 32 字节的密钥。
Poly1305 消息认证码的输入为 32 字节(256bit)的密钥和任意长度的消息比特流,经过一系列计算生成 16 字节(128bit)的摘要。
let str = "欢迎访问hangge.com" let key = "hg012345678901234567890123456789" let mac = try! Poly1305(key: key.bytes).authenticate(str.bytes) print("原始字符串:\(str)") print("key:\(key)") print("Poly1305运算结果:\(mac.toHexString())")运行结果如下:
五、PBKDF2 加密
1,给密码加盐(Salt)
(1)什么是加盐?
在密码学中,通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
(2)为什么要加盐?
- 过去我们为了防止因为数据库的泄露,而造成里面保存的用户名和密码的泄露。通常的做法是不存储明文密码,而是存储加密后的密码,比如存储通过 MD5 或 SHA1 加密后的密文。然而这种方式也是不安全的,只要枚举出所有的常用密码,做成一个索引表,就可以推出来原始密码,这张索引表也被叫做“彩虹表”(之前 csdn 600 万用户明文密码就是一个很好的素材)。
- 而通过加盐,我们在原始密码加上特定的随机字符串字符串,同时再灵活地调整插入的位置。这样即便数据库泄露了,由于密码都是加了 Salt 之后的散列,使用数据字典已经无法直接匹配,明文密码被破解出来的概率也大大降低。即使是暴力破解也需要付出很大的时间成本。
(3)加盐的注意事项
- 盐值不要太短。为了使攻击者无法构造包含所有可能盐值的查询表,盐值越长越好(至少为 8 字节)。一个好的做法是使用和哈希函数输出的字符串等长的盐值,比如 SHA256 算法的输出是 256bits(32 bytes),那么盐值也至少应该是 32 个随机字节。
- 盐要求的是随机性,采用固定盐在数学上等于没加盐。比如我们对用户密码加密,每个用户的盐都应该是不同的,数据库可以这样存储:
注意:不建议将用户名作为盐值。
尽管在一个网站中用户名是唯一的,但是它们是可预测的,并且经常重复用于其他服务中。攻击者可以针对常见用户名构建查询表,然后对用户名盐值哈希发起进攻。
尽管在一个网站中用户名是唯一的,但是它们是可预测的,并且经常重复用于其他服务中。攻击者可以针对常见用户名构建查询表,然后对用户名盐值哈希发起进攻。
2,PBKDF2 介绍
- PBKDF2(Password-Based Key Derivation Function)是一个用来导出密钥的函数,常用于生成加密的密码。
- 它的基本原理是通过一个伪随机函数(例如 HMAC 函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。
- 如果重复的次数足够大,破解的成本就会变得很高。而盐值的添加也会增加“彩虹表”攻击的难度。
3,使用 PBKDF2 给密码加盐
(1)我们可以使用 CryptoSwift 提供的 PKCS5.PBKDF2() 函数进行加盐计算,该函数参数如下:
- password:用来生成密钥的原始密码
- salt:加密用的盐值
- iterations:重复计算的次数。默认值:4096
- keyLength:期望得到的密钥的长度。默认值:不指定
- variant:加密使用的伪随机函数。默认值:sha256
(2)这里我们使用该函数对一个指定密码加盐,其它参数不改变,都使用默认值。
let password = "hangge2017" let salt = "Ut3Opm78U76VbwoP4Vx6UdfN234Esaz9" let pbkdf2 = try! PKCS5.PBKDF2(password: password.bytes, salt: salt.bytes).calculate() print("原始密码:\(password)") print("Salt:\(salt)") print("加盐运算结果:\(pbkdf2.toHexString())")运行结果如下:
(3)可以指定生成的密钥长度,比如这里设置为 4 个字节。
let password = "hangge2017" let salt = "Ut3Opm78U76VbwoP4Vx6UdfN234Esaz9" let pbkdf2 = try! PKCS5.PBKDF2(password: password.bytes, salt: salt.bytes, keyLength: 4).calculate() print("原始密码:\(password)") print("Salt:\(salt)") print("加盐运算结果:\(pbkdf2.toHexString())")那么得到密钥可以转为 8 个字符的字符串:
(4)下面我们改用 md5 算法来进行加盐计算。
let password = "hangge2017" let salt = "Ut3Opm78U76VbwoP4Vx6UdfN234Esaz9" let pbkdf2 = try! PKCS5.PBKDF2(password: password.bytes, salt: salt.bytes, iterations: 4096, variant: .md5).calculate() print("原始密码:\(password)") print("Salt:\(salt)") print("加盐运算结果:\(pbkdf2.toHexString())")运行结果如下:
一般app的话使用哪一种加密就可以了呢航哥