代码之家  ›  专栏  ›  技术社区  ›  Daniel

Swift:如何从Swift调用CCKeyDerivationPBKDF

  •  11
  • Daniel  · 技术社区  · 10 年前

    我正在尝试从Swift调用CCKeyDerivationPBKDF。

    我已经在我的项目桥接标头中导入了所需的标头。h:

    #import <CommonCrypto/CommonKeyDerivation.h>
    

    (顺便说一句,桥接头似乎可以正确导入我项目中的其他Objective C代码)。

    在Xcode中,我可以从.swift文件跳转到此处所示的定义:

    int 
    CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
                          const uint8_t *salt, size_t saltLen,
                          CCPseudoRandomAlgorithm prf, uint rounds, 
                          uint8_t *derivedKey, size_t derivedKeyLen)
    

    最后,当我尝试这样调用函数时:

    let result = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), NSString(password).UTF8String, size_t(passwordLength), UnsafePointer<UInt8>(salt.bytes), size_t(salt.length), CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), uint(actualRoundCount), UnsafeMutablePointer<UInt8>(derivedKey.mutableBytes), size_t(derivedKey.length));
    

    …我收到此编译器错误:

    无法使用类型为“”的参数列表调用“init”(CCPBKDFAlgorithm, UnsafePointer,size_t,UnsafePpointer,size_t, CCPseudo随机算法,uint,UnsafeMutablePointer,size_t)'

    我相信所有的强制转换都是正确的(实际上编译器错误帮助我识别了每个参数的每个问题)-这让我认为编译器理解了我调用CCKeyDerivationPBKDF的意图。

    然而,在所有其他转换错误消失后,编译器感到困惑,并认为我正在尝试用初始化器构造类。

    希望有人能告诉我我的错误。

    (Xcode 6 beta 7)

    根据要求,上下文中的完整代码:

    class func generateAesKeyForPassword(password: String, salt: NSData, roundCount: UInt?, error: NSErrorPointer) -> (key: NSData, actualRoundCount: UInt)?
        {
            let derivedKey = NSMutableData(length: kCCKeySizeAES256)
    
            let passwordLength = size_t(password.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
    
            var actualRoundCount: UInt
    
            if roundCount != nil
            {
                actualRoundCount = roundCount!
            }
            else
            {
                actualRoundCount = UInt(CCCalibratePBKDF(CCPBKDFAlgorithm(kCCPBKDF2), passwordLength, UInt(salt.length), CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), UInt(derivedKey.length), UInt32(300) /* milliseconds */));
            }
    
            let result = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), NSString(password).UTF8String, size_t(passwordLength), UnsafePointer<UInt8>(salt.bytes), size_t(salt.length), CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), uint(actualRoundCount), UnsafeMutablePointer<UInt8>(derivedKey.mutableBytes), size_t(derivedKey.length));
            if result != 0
            {
                let errorDescription = "CCKeyDerivationPBKDF failed with error: '\(result)'"
    
                error.memory = MyError(domain: ClientErrorType.errorDomain, code: Int(result), descriptionText: errorDescription)
    
                return nil
            }
    
            return (NSData(data: derivedKey), actualRoundCount)
        }
    
    2 回复  |  直到 10 年前
        1
  •  15
  •   Panda Naman    7 年前

    斯威夫特3:

    基于密码的密钥派生既可以用于从密码文本派生加密密钥,也可以用于保存密码以进行身份验证。

    有几种哈希算法可以使用,包括由该示例代码提供的SHA1、SHA256、SHA512。

    rounds参数用于使计算变慢,以便攻击者每次尝试都要花费大量时间。典型的延迟值在100ms到500ms之间,如果性能不可接受,可以使用更短的值。

    此示例需要Common Crypto
    有必要为项目设置一个桥接头:
    #import <CommonCrypto/CommonCrypto.h>
    添加 Security.framework 项目。

    参数:

    password     password String  
    salt         salt Data  
    keyByteCount number of key bytes to generate
    rounds       Iteration rounds
    
    returns      Derived key
    
    
    func pbkdf2SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
        return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
    }
    
    func pbkdf2SHA256(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
        return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
    }
    
    func pbkdf2SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
        return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
    }
    
    func pbkdf2(hash :CCPBKDFAlgorithm, password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
        let passwordData = password.data(using:String.Encoding.utf8)!
        var derivedKeyData = Data(repeating:0, count:keyByteCount)
    
        let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
            salt.withUnsafeBytes { saltBytes in
    
                CCKeyDerivationPBKDF(
                    CCPBKDFAlgorithm(kCCPBKDF2),
                    password, passwordData.count,
                    saltBytes, salt.count,
                    hash,
                    UInt32(rounds),
                    derivedKeyBytes, derivedKeyData.count)
            }
        }
        if (derivationStatus != 0) {
            print("Error: \(derivationStatus)")
            return nil;
        }
    
        return derivedKeyData
    }
    

    示例用法:

    let password     = "password"
    //let salt       = "saltData".data(using: String.Encoding.utf8)!
    let salt         = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
    let keyByteCount = 16
    let rounds       = 100000
    
    let derivedKey = pbkdf2SHA1(password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
    print("derivedKey (SHA1): \(derivedKey! as NSData)")
    

    示例输出:

    derivedKey (SHA1): <6b9d4fa3 0385d128 f6d196ee 3f1d6dbf>
    

    雨燕2.x:

    参数类型和类到实例方法的细微更改用于测试。

    func generateAesKeyForPassword(password: String, salt: NSData, roundCount: Int?, error: NSErrorPointer) -> (key: NSData, actualRoundCount: UInt32)?
    {
        let nsDerivedKey = NSMutableData(length: kCCKeySizeAES256)
        var actualRoundCount: UInt32
    
        // Create Swift intermediates for clarity in function calls
        let algorithm: CCPBKDFAlgorithm        = CCPBKDFAlgorithm(kCCPBKDF2)
        let prf:       CCPseudoRandomAlgorithm = CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256)
        let saltBytes  = UnsafePointer<UInt8>(salt.bytes)
        let saltLength = size_t(salt.length)
        let nsPassword        = password as NSString
        let nsPasswordPointer = UnsafePointer<Int8>(nsPassword.cStringUsingEncoding(NSUTF8StringEncoding))
        let nsPasswordLength  = size_t(nsPassword.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
        var nsDerivedKeyPointer = UnsafeMutablePointer<UInt8>(nsDerivedKey.mutableBytes)
        let nsDerivedKeyLength = size_t(nsDerivedKey.length)
        let msec: UInt32 = 300
    
        if roundCount != nil {
            actualRoundCount = UInt32(roundCount!)
        }
        else {
            actualRoundCount = CCCalibratePBKDF(
                algorithm,
                nsPasswordLength,
                saltLength,
                prf,
                nsDerivedKeyLength,
                msec);
        }
    
        let result = CCKeyDerivationPBKDF(
            algorithm,
            nsPasswordPointer,   nsPasswordLength,
            saltBytes,           saltLength,
            prf,                 actualRoundCount,
            nsDerivedKeyPointer, nsDerivedKeyLength)
    
        if result != 0 {
            let errorDescription = "CCKeyDerivationPBKDF failed with error: '\(result)'"
            // error.memory = MyError(domain: ClientErrorType.errorDomain, code: Int(result), descriptionText: errorDescription)
            return nil
        }
    
        return (nsDerivedKey, actualRoundCount)
    }
    

    //增加的奖金:

    func salt(#length:UInt) -> NSData {
        let salt        = NSMutableData(length: Int(length))
        var saltPointer = UnsafeMutablePointer<UInt8>(salt.mutableBytes)
        SecRandomCopyBytes(kSecRandomDefault, length, saltPointer);
        return salt
    }
    

    //测试呼叫:

    let password   = "test pass"
    let salt       = self.salt(length:32)
    let roundCount = 300
    var error: NSError?
    
    let result = self.generateAesKeyForPassword(password, salt:salt, roundCount:roundCount, error:&error)
    println("result: \(result)")
    

    输出:

    result: Optional((<d279ab8d 8ace67b7 abec844c b9979d20 f2bb0a7f 5af70502 085bf1e4 1016b20c>, 300))
    
        2
  •  1
  •   Daniel    10 年前

    所以我认为这是可行的:

    let result = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), NSString(string: password).UTF8String, size_t(passwordLength), UnsafePointer<UInt8>(salt.bytes), size_t(salt.length), CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), uint(actualRoundCount), UnsafeMutablePointer<UInt8>(derivedKey.mutableBytes), size_t(derivedKey.length));
    

    在Swift 1.2+中,size_t转换不再是必需的:

    let result = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), NSString(string: password).UTF8String, passwordLength, UnsafePointer<UInt8>(salt.bytes), salt.length, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA512), uint(actualRoundCount), UnsafeMutablePointer<UInt8>(derivedKey.mutableBytes), derivedKey.length)
    

    请注意,这是错误的:

    NSString(password).UTF8String
    

    应该是:

    NSString(string: password).UTF8String
    

    编译器错误绝对是误导性的(仍然是测试版)