簡體   English   中英

用於Java后端加密解密的iOS橢圓曲線密鑰

[英]iOS Elliptical curve key used for encryption decryption with Java Backend

我是一名 iOS 開發人員,並嘗試使用 Secure enclave 生成​​ ECC 對密鑰。 我可以使用這里的示例應用程序成功地做到這一點: https : //github.com/agens-no/EllipticCurveKeyPair 當我使用這個密鑰和 Python 實現來進行這里提到的加密和解密時: https : //gist.github.com/dschuetz/2ff54d738041fc888613f925a7708a06它可以工作。

問題是我需要一個 Java 代碼來做同樣的事情。 任何人都可以幫助我實現這一目標,或者向我指出與 Python 代碼執行相同工作的代碼。

在 iOS 方面,我正在做eciesEncryptionStandardX963SHA256AESGCM加密和解密邏輯。

我知道我應該嘗試自己解決這個問題。 但我是一名 iOS 工程師,正在嘗試使用 Java 后端。 如果有人可以指導我,那將非常有幫助。


根據答案創建了一個示例 Java 代碼。 代碼鏈接: https : //gist.github.com/balrajOla/fa2f6030538b20a396c086377a6f7114

使用此處提供的示例 iOS 應用程序: https : //github.com/agens-no/EllipticCurveKeyPair 我生成了 ECC 密鑰。 然后將公鑰傳遞給 Java 代碼以創建加密消息。 此加密消息將傳遞回上述示例 iOS 應用程序,以使用eciesEncryptionStandardX963SHA256AESGCM算法進行解密。 但是我們在快照下面提到了一個錯誤。 在此處輸入圖片說明

我們遇到了同樣的問題。 我們希望從帶有 Java 后端的 iOS 安全飛地帶來一個 EC 密鑰交換。

經過三天的反復試驗,我們終於找到了一個可以工作的Java實現。

Java 代碼取自https://github.com/O2-Czech-Republic/BC-ECIES-for-iOS

和 iOS 代碼,使用eciesEncryptionCofactorVariableIVX963SHA256AESGCM算法:

  static func getExportableKeyFromECKey() -> String? {
        // If exists already a created EC Key, then export the public part
        if let privateKey = self.loadECPrivateKey() {
            if let publicKey = self.getECPublicKey(privateKey) {
                if self.algorithmAcceptedForEC(publicKey) {
                    var error: Unmanaged<CFError>?
                    // Get Public key External represenatation
                    guard let cfdata = SecKeyCopyExternalRepresentation(publicKey, &error) else {
                        return nil
                    }
                    let pubKeyData: Data = cfdata as Data
                    return pubKeyData.base64EncodedString()
                }
            }
        }
            // If no EC Key created, then first create one
        else {
            var error: Unmanaged<CFError>?
            let tag = Config.skName.data(using: .utf8) ?? Data()
            let attributes: [String: Any] = [kSecClass as String: kSecClassKey,
                                             kSecAttrKeyType as String: Config.skType,
                                             kSecAttrKeySizeInBits as String: Config.ecKeySize,
                                             kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: true,
                                                                              kSecAttrApplicationTag as String: tag]]
            do {
                // Create Private Key
                guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
                    throw error!.takeRetainedValue() as Error
                }
                // Get Public Key
                guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
                    throw error!.takeRetainedValue() as Error
                }
                // Get Public key External represenatation
                guard let cfdata = SecKeyCopyExternalRepresentation(publicKey, &error) else {
                    throw error!.takeRetainedValue() as Error
                }
                let pubKeyData: Data = cfdata as Data
                return pubKeyData.base64EncodedString()
            } catch {
                print(error)
            }
        }
        return nil
    }

    static func loadECPrivateKey() -> SecKey? {
        let tag = Config.skName.data(using: .utf8)!
        let query: [String: Any] = [kSecClass as String: kSecClassKey,
                                    kSecAttrApplicationTag as String: tag,
                                    kSecAttrKeyType as String: Config.skType,
                                    kSecReturnRef as String: true]
        var item: CFTypeRef?
        let status = SecItemCopyMatching(query as CFDictionary, &item)
        guard status == errSecSuccess else {
            return nil
        }
        print("LOAD PRIVATE KEY: \n \(item as! SecKey) \n")
        return (item as! SecKey)
    }

    static func getECPublicKey(_ privateKey: SecKey) -> SecKey? {
        guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
            // Can't get public key
            return nil
        }
        return publicKey
    }

    static func algorithmAcceptedForEC(_ publicKey: SecKey) -> Bool {
        guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, Config.ecAlgorithm) else {
            // Algorith not supported
            print("\nEncrytion Algorithm not supported!!!\n")
            return false
        }
        return true
    }

    /// if let encryptedData = Data(base64Encoded: "BOqw779hxsGLMEV7X81Mphcx+SMtxSQs388s5CydkvJ4V2XuuWoyp48GCmgDMBnYlEIRqAdHxIc/Ts3ATxa9ENCDGdIZf5CjpWsOIVXYxLvupdap4w==", options:.ignoreUnknownCharacters) 
    static func decryptStr(_ encData: Data) {
        /// 1. Step: Get the Private Key and decrypt the symmetric key
        let privateKey = loadECPrivateKey()
        guard SecKeyIsAlgorithmSupported(privateKey!, .decrypt, Config.ecAlgorithm) else {
            print("Can't decrypt\nAlgorithm not supported")
            return
        }
        DispatchQueue.global().async {
            var error: Unmanaged<CFError>?
            let clearTextData = SecKeyCreateDecryptedData(privateKey!,
                                                          Config.ecAlgorithm,
                                                          encData as CFData,
                                                          &error) as Data?
            DispatchQueue.main.async {
                guard clearTextData != nil else {
                    print("Can't decrypt")
                    return
                }
                let clearText = String(decoding: clearTextData!, as: UTF8.self)
                print("Decrypted Info: \(clearText)")
                // clearText is our decrypted string
            }
        }
    }

在 Java 中,您有兩個有趣的類 - ECGenParameterSpecKeyPairGenerator ECGenParameterSpec指定生成橢圓曲線域參數的參數, KeyPairGenerator用於生成公私鑰對。

在 Nokilay Elenkov 所著的Android Security Internals一書中,有一個很好的代碼示例,說明它們組合生成密鑰對。

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecParamSpec);
KeyPair keyPair = kpg.generateKeyPair();

這是對前面代碼的解釋

有兩種方法可以初始化 KeyPairGenerator:通過指定所需的密鑰大小和指定特定於算法的參數。 在這兩種情況下,您都可以選擇傳遞一個 SecureRandom 實例以用於密鑰生成。 如果僅指定了密鑰大小,則密鑰生成將使用默認參數(如果有)。 要指定其他參數,您必須實例化和配置適合您使用的非對稱算法的 AlgorithmParameterSpec 實例,並將其傳遞給 initialize() 方法,如例 5-15 所示。 在此示例中,在第 2 行中初始化的 ECGenParameterSpec 是一個 AlgorithmParameterSpec,它允許您指定在生成橢圓曲線 (EC) 加密密鑰時使用的曲線名稱。 它被傳遞給initialize()方法在第3行后,在第4行以后的generateKeyPair()調用將使用指定的曲線(secp256r1)來生成密鑰對。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM