ios/swift 中的椭圆曲线 Diffie Hellman

问题描述 投票:0回答:4

iOS 是否公开用于密钥生成和使用 ECDH 派生密钥的 API?

据我所知,苹果正在内部使用它(特别是 x25519),但我没有看到它通过通用加密或其他方式公开为公共 API。

谢谢,

Z

ios swift cryptography elliptic-curve ecdh
4个回答
31
投票

使用 Xcode 8.3.3 在 Playground 中完成,使用 EC 为 Alice、Bob 生成私钥/公钥,然后使用 Alice 的私钥和 Bob 的公钥计算 Alice 的共享秘密,并使用 Bob 的私钥和 Alice 的公钥为 Bob 共享秘密,最后断言他们是平等的。

import Security
import UIKit

let attributes: [String: Any] =
    [kSecAttrKeySizeInBits as String:      256,
     kSecAttrKeyType as String: kSecAttrKeyTypeEC,
     kSecPrivateKeyAttrs as String:
        [kSecAttrIsPermanent as String:    false]
]

var error: Unmanaged<CFError>?
if #available(iOS 10.0, *) {
    // generate a key for alice
    guard let privateKey1 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }
    let publicKey1 = SecKeyCopyPublicKey(privateKey1)

    // generate a key for bob
    guard let privateKey2 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }
    let publicKey2 = SecKeyCopyPublicKey(privateKey2)

    let dict: [String: Any] = [:]

    // alice is calculating the shared secret
    guard let shared1 = SecKeyCopyKeyExchangeResult(privateKey1, SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256, publicKey2!, dict as     CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }

    // bob is calculating the shared secret
    guard let shared2 = SecKeyCopyKeyExchangeResult(privateKey2, SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256, publicKey1!, dict as CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }

    print(shared1==shared2)


} else {
    // Fallback on earlier versions
    print("unsupported")
}

感谢@Mats 为我指明了正确的方向..3


6
投票

这是 swift 5 的最新代码和参数的变化。

import Security
import UIKit

var error: Unmanaged<CFError>?

let keyPairAttr:[String : Any] = [kSecAttrKeySizeInBits as String: 256,
                                  SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 32,
                                  kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
                                  kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false],
                                  kSecPublicKeyAttrs as String:[kSecAttrIsPermanent as String: false]]
let algorithm:SecKeyAlgorithm = SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256//ecdhKeyExchangeStandardX963SHA256

do {
    guard let privateKey = SecKeyCreateRandomKey(keyPairAttr as CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }
    let publicKey = SecKeyCopyPublicKey(privateKey)
    print("public ky1: \(String(describing: publicKey)),\n private key: \(privateKey)\n\n")



    guard let privateKey2 = SecKeyCreateRandomKey(keyPairAttr as CFDictionary, &error) else {
        throw error!.takeRetainedValue() as Error
    }
    let publicKey2 = SecKeyCopyPublicKey(privateKey2)
    print("public ky2: \(String(describing: publicKey2)),\n private key2: \(privateKey2)\n\n")



    let shared:CFData? = SecKeyCopyKeyExchangeResult(privateKey, algorithm, publicKey2!, keyPairAttr as CFDictionary, &error)
    let sharedData:Data = shared! as Data
    print("shared Secret key: \(sharedData.hexEncodedString())\n\n")

    let shared2:CFData? = SecKeyCopyKeyExchangeResult(privateKey2, algorithm, publicKey!, keyPairAttr as CFDictionary, &error)
    let sharedData2:Data = shared2! as Data
    print("shared Secret key 2: \(sharedData2.hexEncodedString())\n\n")

    // shared secret key and shared secret key 2 should be same

} catch let error as NSError {
    print("error: \(error)")
} catch  {
    print("unknown error")
}

extension Data {
    struct HexEncodingOptions: OptionSet {
        let rawValue: Int
        static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
    }

    func hexEncodedString(options: HexEncodingOptions = []) -> String {
        let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
        return self.map { String(format: format, $0) }.joined()
    }
}

2
投票

大约 - 2020 和 iOS13。在下面 Zohar 的代码片段中,在尝试获取共享秘密之前,还要在字典中指定密钥大小。

let dict: [String: Any] = [SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 32]

否则会出现错误。

kSecKeyKeyExchangeParameterRequestedSize
不见了


0
投票

您可以使用 CryptoKit (iOS13+) 实现同样的效果

import CryptoKit
import Foundation

var protocolSalt = "Hello, playground".data(using: .utf8)!


// generate key pairs
let sPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let sPublicKey = sPrivateKey.publicKey


let rPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let rPublicKey = rPrivateKey.publicKey

// sender derives symmetric key
let sSharedSecret = try! sPrivateKey.sharedSecretFromKeyAgreement(with: rPublicKey)
let sSymmetricKey = sSharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self,
                                                          salt: protocolSalt,
                                                          sharedInfo: Data(),
                                                          outputByteCount: 32)

let sSensitiveMessage = "The result of your test is positive".data(using: .utf8)!

// sender encrypts data
let encryptedData = try! ChaChaPoly.seal(sSensitiveMessage, using: sSymmetricKey).combined

// receiver derives same symmetric key
let rSharedSecret = try! rPrivateKey.sharedSecretFromKeyAgreement(with: sPublicKey)
let rSymmetricKey = rSharedSecret.hkdfDerivedSymmetricKey(using: SHA256.self,
                                                          salt: protocolSalt,
                                                          sharedInfo: Data(),
                                                          outputByteCount: 32)

// receiver decrypts data
let sealedBox = try! ChaChaPoly.SealedBox(combined: encryptedData)
let decryptedData = try! ChaChaPoly.open(sealedBox, using: rSymmetricKey)
let rSensitiveMessage = String(data: decryptedData, encoding: .utf8)!

// assertions
sSymmetricKey == rSymmetricKey
sSensitiveMessage == decryptedData

来源

文章

© www.soinside.com 2019 - 2024. All rights reserved.