首先,这是一个非常不安全的密钥推导函数。任何严肃的加密方案都不应该使用这个。要从密码创建密钥,必须使用PBKDF(基于密码的密钥派生函数),如PBKDF2。
出于兼容性的目的,您可能需要实现这个破碎的方案,所以我将在这里深入探讨。
密钥基本上是数据。您已经创建了一个十六进制编码的字符串,然后对其进行了Base64编码。这使得结果数据的长度是它应该的两倍。你的意思是:
public extension SymmetricKey {
var base64: String {
self.withUnsafeBytes { body in
Data(body).base64EncodedString()
}
}
init(pass: String) {
let hash = SHA256.hash(data: Data(pass.utf8)).withUnsafeBytes { ptr in
Data(ptr)
}
self.init(data: hash)
}
}
let key1 = SymmetricKey(size: .bits256).base64
let key2 = SymmetricKey(pass: "12345").base64
不幸的是,苹果的CryptoKit不包括任何适当的PBKDF。它是一个非常有限的框架,只为一些非常特定的用例提供原语。提供所需工具的一些流行框架是
CryptoSwift
和
IDZSwiftCommonCrypto
。更通用的方法是使用苹果的CommonCryptor,但Swift并不是特别有趣。
然而,这里有一个例子。
public extension SymmetricKey {
var base64: String {
self.withUnsafeBytes { body in
Data(body).base64EncodedString()
}
}
init(password: String, salt: Data) {
self.init(data: Self.makeKey(forPassword: password, withSalt: salt))
}
private static func makeKey(forPassword password: String, withSalt salt: Data) -> Data {
let passwordArray = password.utf8.map(Int8.init)
let saltArray = Array(salt)
let keySize = 32
var derivedKey = Array<UInt8>(repeating: 0, count: keySize)
let algorithm = CCPBKDFAlgorithm(kCCPBKDF2)
let prf = CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1)
let pbkdf2Rounds = UInt32(10000)
let result = CCCryptorStatus(
CCKeyDerivationPBKDF(
algorithm,
passwordArray, passwordArray.count,
saltArray, saltArray.count,
prf, pbkdf2Rounds,
&derivedKey, keySize)
)
guard result == CCCryptorStatus(kCCSuccess) else {
fatalError("SECURITY FAILURE: Could not derive secure password (\(result))")
}
return Data(derivedKey)
}
}
称之为需要传递盐。如何选择盐在一定程度上取决于你的使用情况。一种常见的情况是,每次加密都使用随机盐(比如16个字节),然后将盐与加密数据一起传递,以便接收器可以解密。这是一种制作这种随机数据的方法:
func makeSalt(length: Int) -> Data {
var data = Data(count: length)
data.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, length, $0.baseAddress!)
}
return data
}
您还可以在上述框架中获得执行这些操作的函数。在Swift中做密码学几乎没有什么乐趣。