【问题标题】:CCKeyDerivationPBKDF using HMAC SHA1 often return -1CCKeyDerivationPBKDF 使用 HMAC SHA1 经常返回 -1
【发布时间】:2014-12-27 19:25:31
【问题描述】:

当我使用来自#import <CommonCrypto/CommonKeyDerivation.h>CCKeyDerivationPBKDF 时,它返回-1,这是一个未定义的结果。我不知道我是否错过了什么。如果我使用HMAC MD5 或其他算法,它可以返回成功,并且只有当我使用HMAC SHA1 时,它才会返回错误状态。

int feedback = CCKeyDerivationPBKDF(kCCPBKDF2, clearTextData.bytes, clearTextData.length, secretData.bytes, secretData.length, kCCHmacAlgSHA1, 2048, result, sizeof(result)); 

【问题讨论】:

  • 您需要显示所有必要的代码。所有变量是如何定义的。

标签: ios objective-c


【解决方案1】:

我注意到您使用的是kCCHmacAlgSHA1 而不是kCCPRFHmacAlgSHA1,这可能是错误。

这对我有用:

NSData *keyData = [@"password" dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt    = [@"salt" dataUsingEncoding:NSUTF8StringEncoding];
uint    rounds  = 2048;
uint    keySize = kCCKeySizeAES128;

NSMutableData *derivedKey = [NSMutableData dataWithLength:keySize];

CCKeyDerivationPBKDF(kCCPBKDF2,               // algorithm
                     keyData.bytes,           // password
                     keyData.length,          // passwordLength
                     salt.bytes,              // salt
                     salt.length,             // saltLen
                     kCCPRFHmacAlgSHA1,       // PRF
                     rounds,                  // rounds
                     derivedKey.mutableBytes, // derivedKey
                     derivedKey.length);      // derivedKeyLen

NSLog(@"derivedKey: %@", derivedKey);

输出:
derivedKey: <2c13cb7a d3468748 5c3f3d4f 18ebddbd>

斯威夫特 3

let password = "TestPassword"
let salt     = Data("salt" .utf8);
let keySize  = kCCKeySizeAES128;
let rounds   = 2048

var derivedKeyData = Data(repeating:0, count:keySize)

let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
    salt.withUnsafeBytes { saltBytes in

        CCKeyDerivationPBKDF(
            CCPBKDFAlgorithm(kCCPBKDF2),
            password, password.utf8.count,
            saltBytes, salt.count,
            UInt32(kCCPRFHmacAlgSHA1),
            UInt32(rounds),
            derivedKeyBytes,
            derivedKeyData.count)
    }
}

print("derivedKeyData: \(derivedKeyData.map { String(format: "%02hhx", $0) }.joined())")

输出:
derivedKeyData: 75d1f85fd64d170b3ffe66c7f1d1519a

来自日落文档部分的更通用的解决方案:

基于密码的密钥派生 2 (Swift 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>

基于密码的密钥派生校准 (Swift 3+)

确定在当前平台上用于特定延迟的 PRF 轮数。

几个参数默认为代表值,不会对轮数产生重大影响。

password Sample password.  
salt     Sample salt.  
msec     Targeted duration we want to achieve for a key derivation.

returns  The number of iterations to use for the desired processing time.


func pbkdf2SHA1Calibrate(password: String, salt: Data, msec: Int) -> UInt32 {
    let actualRoundCount: UInt32 = CCCalibratePBKDF(
        CCPBKDFAlgorithm(kCCPBKDF2),
        password.utf8.count,
        salt.count,
        CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
        kCCKeySizeAES256,
        UInt32(msec));
    return actualRoundCount
}

示例用法:

let saltData       = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let passwordString = "password"
let delayMsec      = 100

let rounds = pbkdf2SHA1Calibrate(password:passwordString, salt:saltData, msec:delayMsec)
print("For \(delayMsec) msec delay, rounds: \(rounds)")

示例输出:

For 100 msec delay, rounds: 93457

【讨论】:

  • 我将您的代码与 Swift 3 解决方案一起使用,它工作正常,但一个问题是 .withUnsafeMutableBytes 给出错误“重叠访问 'derivedKeyData',但修改需要独占访问;考虑复制到本地多变的”。你能更新代码吗@zaph
猜你喜欢
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 2012-10-12
  • 1970-01-01
相关资源
最近更新 更多