当前位置: > > > Swift - 第三方加密库CryptoSwift使用详解2(CRC、MAC、PBKDF2)

Swift - 第三方加密库CryptoSwift使用详解2(CRC、MAC、PBKDF2)

三、CRC 校验码计算

CRC 即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。
循环冗余检查(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

HMACHashed Message Authentication Code)中文名叫做:散列消息身份验证码。关于它的具体介绍可以参考我之前写的这篇文章:Swift - 如何实现字符串的HMAC_SHA1加密
当时使用的是 iOS SDK 自带的 CommonCrypto 库来实现,如果我们使用 CryptoSwift 的话就更简单了。

(1)下面是一个进行 HMAC_SHA1 计算的样例。
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,我们还可以使用其它算法比如 MD5SHA256
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

Poly1305Daniel.J.Bernstein 创建的消息认证码,可用于检测消息的完整性和验证消息的真实性,现常在网络安全协议(SSL/TLS)中与 salsa20ChaCha20 流密码结合使用。
Poly1305 消息认证码的输入为 32 字节(256bit)的密钥和任意长度的消息比特流,经过一系列计算生成 16 字节(128bit)的摘要。
使用代码如下,这里我们还是使用一个字符串来生成一个 32 字节的密钥。
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)为什么要加盐?
  • 过去我们为了防止因为数据库的泄露,而造成里面保存的用户名和密码的泄露。通常的做法是不存储明文密码,而是存储加密后的密码,比如存储通过 MD5SHA1 加密后的密文。然而这种方式也是不安全的,只要枚举出所有的常用密码,做成一个索引表,就可以推出来原始密码,这张索引表也被叫做“彩虹表”(之前 csdn 600 万用户明文密码就是一个很好的素材)。
  • 而通过加盐,我们在原始密码加上特定的随机字符串字符串,同时再灵活地调整插入的位置。这样即便数据库泄露了,由于密码都是加了 Salt 之后的散列,使用数据字典已经无法直接匹配,明文密码被破解出来的概率也大大降低。即使是暴力破解也需要付出很大的时间成本。

(3)加盐的注意事项
  • 盐值不要太短。为了使攻击者无法构造包含所有可能盐值的查询表,盐值越长越好(至少为 8 字节)。一个好的做法是使用和哈希函数输出的字符串等长的盐值,比如 SHA256 算法的输出是 256bits32 bytes),那么盐值也至少应该是 32 个随机字节。
  • 盐要求的是随机性,采用固定盐在数学上等于没加盐。比如我们对用户密码加密,每个用户的盐都应该是不同的,数据库可以这样存储:
注意:不建议将用户名作为盐值
尽管在一个网站中用户名是唯一的,但是它们是可预测的,并且经常重复用于其他服务中。攻击者可以针对常见用户名构建查询表,然后对用户名盐值哈希发起进攻。

2,PBKDF2 介绍

  • PBKDF2Password-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())")
运行结果如下:  
评论0