简体   繁体   中英

CCKeyDerivationPBKDF using HMAC SHA1 often return -1

while I'm using CCKeyDerivationPBKDF from #import <CommonCrypto/CommonKeyDerivation.h> , and it return -1 which is an undefined result. I don't know whether I miss something. It can return Success if I use HMAC MD5 or other algorithms and only if I use HMAC SHA1 it will return the bad status.

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

I notice you are using kCCHmacAlgSHA1 instead of kCCPRFHmacAlgSHA1 , that is probably the error.

This works for me:

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);

Output:
derivedKey: <2c13cb7a d3468748 5c3f3d4f 18ebddbd>

Swift 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())")

Output:
derivedKeyData: 75d1f85fd64d170b3ffe66c7f1d1519a

A more general solution from the sunsetted documentation section:

Password Based Key Derivation 2 (Swift 3+)

Password Based Key Derivation can be used both for deriving an encryption key from password text and saving a password for authentication purposes.

There are several hash algorithms that can be used including SHA1, SHA256, SHA512 which are provided by this example code.

The rounds parameter is used to make the calculation slow so that an attacker will have to spend substantial time on each attempt. Typical delay values fall in the 100ms to 500ms, shorter values can be used if there is unacceptable performance.

This example requires Common Crypto
It is necessary to have a bridging header to the project:
#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework to the project.

Parameters:

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
}

Example usage:

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)")

Example Output:

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

Password Based Key Derivation Calibration (Swift 3+)

Determine the number of PRF rounds to use for a specific delay on the current platform.

Several parameters are defaulted to representative values that should not materially affect the round count.

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
}

Example usage:

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)")

Example Output:

For 100 msec delay, rounds: 93457

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM