11

Swift から CCKeyDerivationPBKDF を呼び出そうとしています。

Project-Bridging-Header.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));

...次のコンパイラ エラーが発生します。

タイプ '(CCPBKDFAlgorithm, UnsafePointer, size_t, UnsafePointer, size_t, CCPseudoRandomAlgorithm, uint, UnsafeMutablePointer, size_t)' の引数リストで 'init' を呼び出すことはできません

私はすべてのキャストが正しいと信じています (実際、コンパイラ エラーは、各パラメーターの各問題を特定するのに役立ちました) - これにより、コンパイラは CCKeyDerivationPBKDF を呼び出す意図を理解していると思います。

ただし、他のすべてのキャスト エラーが解消された後、コンパイラは混乱し、初期化子を使用してクラスを構築しようとしていると認識します。

誰かが私のやり方の誤りを教えてくれることを願っています。

(Xcode 6 ベータ 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)
    }
4

2 に答える 2

15

スウィフト 3:

パスワード ベースのキー導出は、パスワード テキストから暗号化キーを導出することと、認証目的でパスワードを保存することの両方に使用できます。

このコード例で提供されている SHA1、SHA256、SHA512 など、使用できるハッシュ アルゴリズムがいくつかあります。

rounds パラメーターは、計算を遅くするために使用されるため、攻撃者は試行ごとにかなりの時間を費やさなければなりません。一般的な遅延値は 100 ミリ秒から 500 ミリ秒です。パフォーマンスが許容できない場合は、より短い値を使用できます。

この例では 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))
于 2014-09-06T17:22:46.770 に答える
1

だから私はこれがうまくいくと信じています:

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

コンパイラ エラーは間違いなく誤解を招くものでした (まだベータ版)

于 2014-09-05T18:50:46.623 に答える