我有类似的需求,需要在用户输入密码进入应用程序时加密所有字符串,以便那些敏感字符串不会一直保持未加密状态。因此,我必须将这些字符串保持加密状态,并仅在需要时解密。
这是一个简单的要求,我希望保持轻量级。因此,我创建了一个小混淆器,使用@RobNapier在他的博客中分享的许多有用信息。它可能对那些正在寻找具有许多有趣评论的轻量级解决方案的人有所帮助。
import Foundation
import CommonCrypto
// 与接口交互的薄包装
public enum CrypticAlgo {
case AlgoAES
case AlgoDES
func blockSize() -> Int {
switch self {
case .AlgoAES:
return kCCBlockSizeAES128
case .AlgoDES:
return kCCBlockSizeDES
}
}
func keySize() -> size_t {
switch self {
case .AlgoAES:
return kCCKeySizeAES128
case .AlgoDES:
return kCCKeySizeDES
}
}
func algo() -> UInt32 {
switch self {
case .AlgoAES:
return CCAlgorithm(kCCAlgorithmAES)
case .AlgoDES:
return CCAlgorithm(kCCAlgorithmDES)
}
}
}
公共最终类 MGObfuscate {
私有变量ivData:[UInt8]?
私有变量derivedKey:数据?
私有让crypticAlgo:CrypticAlgo
公共init(密码:字符串,盐:字符串,algo:CrypticAlgo){
//快速获取数据以释放密码字符串
let passwordData = password.data(使用:.utf8)!
//
//需要回合以在生成哈希时延迟1秒。
// Salt是一个公共属性。如果攻击者以某种方式获得了drivedKey并尝试破解
//通过暴力攻击密码,由于Rounds的延迟,将使其感到沮丧
//获取实际密码并阻止他/她的努力。
//
让回合= CCCalibratePBKDF(CCPBKDFAlgorithm(kCCPBKDF2),密码计数,
盐计数,CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),Int(CC_SHA256_DIGEST_LENGTH),1000)
让saltData = salt.data(使用:.utf8)!
derivedKey = MGObfuscate.derivedKey(for:passwordData,
saltData:saltData,rounds:rounds)
self.crypticAlgo = algo
var ivData = [UInt8](重复:0,计数:algo.blockSize())
//用于初始化向量的随机加密安全字节
让rStatus = SecRandomCopyBytes(kSecRandomDefault,ivData.count,&ivData)
self.ivData = ivData
// print(ivData)
守卫rStatus == errSecSuccess else {
fatalError(“种子未生成\(rStatus)”)
}
}
@inline(__always)私有静态函数派生密钥(for passwordData:数据,saltData:数据,rounds:UInt32) ->数据{
var derivedData = Data(count:Int(CC_SHA256_DIGEST_LENGTH))
让结果= derivedData.withUnsafeMutableBytes {(drivedBytes:UnsafeMutablePointer<UInt8>?)在
passwordData.withUnsafeBytes({(passwordBytes:UnsafePointer<Int8>!)在
saltData.withUnsafeBytes({(saltBytes:UnsafePointer<UInt8>!)在
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),passwordBytes,passwordData.count,saltBytes,saltData.count,CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),rounds,drivedBytes,Int(CC_SHA256_DIGEST_LENGTH))
})
})
}
如果kCCSuccess!=结果{
fatalError(“无法为密码生成哈希”)
}
返回derivedData
}
私有func runCryptic(operation:Int,inputData:Data,keyData:Data,ivData:Data) ->数据{
让cryptLength = size_t(inputData.count + crypticAlgo.blockSize())
var cryptData = Data(count:cryptLength)
让keyLength = crypticAlgo.keySize()
var bytesProcessed:size_t = 0
让cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
inputData.withUnsafeBytes { dataBytes in
keyData.withUnsafeBytes { keyBytes in
ivData.withUnsafeBytes{ ivBytes in
CCCrypt(CCOperation(operation),
crypticAlgo.algo(),
CCOptions(kCCOptionPKCS7Padding),
keyBytes,keyLength,
ivBytes,
dataBytes,inputData.count,
cryptBytes,cryptLength,
&bytesProcessed)
}
}
}
}
如果cryptStatus == CCCryptorStatus(kCCSuccess){
cryptData.removeSubrange(bytesProcessed..<cryptData.count)
} else {
fatalError(“错误:\(cryptStatus)”)
}
返回cryptData
}
公共func encriptAndPurge(inputString:inout String?) ->数据?{
如果let inputdata = inputString?.data(使用:.utf8){
inputString = nil
返回runCryptic(operation:
}