簡體   English   中英

讀取 Swift 中 Java 服務器發送的公鑰

[英]Reading Public Key Sent by Java Server in Swift

我正在嘗試從 Java 服務器讀取公鑰(x509 格式編碼)以完成我的橢圓曲線 Diffie Hellman Exchange。 我可以毫無問題地將公鑰發送到服務器,但現在我想讀取服務器發送給 iOS 客戶端的公鑰。

byte[] serverPubKeyEnc = serverKpair.getPublic().getEncoded(); (This is on the server)

這就是我返回到 iOS 方面的內容。 為了處理它,我需要從輸入 stream 中讀取它,然后將其轉換為可用的公鑰。 這就是我現在在 iOS 方面的閱讀關鍵:

 var error: Unmanaged<CFError>? = nil
    
    let mutableData = CFDataCreateMutable(kCFAllocatorDefault, CFIndex(0))
        if mutableData != nil
        {
            let headerSize = 26
         
            //For importing Java key data
            CFDataAppendBytes(mutableData, CFDataGetBytePtr(data as CFData), CFDataGetLength(data as CFData))
            CFDataDeleteBytes(mutableData, CFRangeMake(CFIndex(0), headerSize))

            //Use the mutableData here (SecKeyCreateWithData)
            let publicKey = SecKeyCreateWithData(
                mutableData!,
                [
                    kSecAttrKeyType: kSecAttrKeyTypeEC,
                    kSecAttrKeyClass: kSecAttrKeyClassPublic,
                ] as NSDictionary,
                &error)
            
            let fullKey = SecKeyCopyExternalRepresentation(publicKey!, &error)
            
            return fullKey!
        }

在這里我可以讀到“publicKey”,我知道它里面有一些價值。 我怎樣才能把它變成一個可用的密鑰來生成共享密鑰?

TLDR:我想讀取來自 Java 服務器 (ECDH) 的公鑰,以在 iOS 客戶端中生成用於加密的對稱密鑰。

完整的流程如下所示:

  • 從服務器端使用公鑰接收 91 個字節
  • 使用 SecKeyCreateWithData 創建一個 SecKey
  • 使用 SecKeyCreateRandomKey 在 iOS 上創建密鑰對
  • 將自己的公鑰發送到服務器端
  • 服務器端可以使用該信息計算共享密鑰
  • 客戶端使用 SecKeyCopyKeyExchangeResult 計算共享密鑰
  • 如果一切正確,它應該在 iOS 和 Java 端提供相同的共享密鑰

因此,為了得到一個完整的測試用例,可以編寫一個生成密鑰對的 Java 程序。 為簡單起見,可以復制/粘貼 Java 和 iOS 應用程序之間的公鑰進行測試,而不是使用網絡連接。 Java 程序將公鑰寫入控制台。 將此密鑰復制到 Swift 源代碼中。 Swift 程序已編譯並生成密鑰對。 公鑰被復制/粘貼到 Java 程序,該程序在控制台上讀取它。 兩個程序然后 output 計算的共享密鑰,由於顯而易見的原因應該是相同的,因為它用於進一步的對稱加密。

這個很好的答案https://stackoverflow.com/a/26502285/2331445提供了將十六進制字符串轉換為數據並返回的實用方法。

iOS Swift 代碼

以下代碼假定使用 secp256r1 曲線,密鑰大小為 256 位。

所描述的流程可以實現如下:

    let otherKey = "3059301306072a8648ce3d020106082a8648ce3d03010703420004df96b3c0c651707c93418781b91782319f6e798550d954c46ac7318c7eac130f96380991a93049059e03e4190dd147b64d6ebc57320938f026844bda3de22352".hexadecimal!
    
    guard let otherPublicKey = otherPublicKey(data: otherKey) else { return }
    guard let ownPrivateKey = createOwnKey() else { return }
    guard let ownPublicKey = SecKeyCopyPublicKey(ownPrivateKey) else { return }
    
    send(ownPublicKey: ownPublicKey)
    
    if let sharedSecret = computeSharedSecret(ownPrivateKey: ownPrivateKey, otherPublicKey: otherPublicKey) {
        print("shared secret: \(sharedSecret.hexadecimal)")
    } else {
        print("shared secret computation failed")
    }
    

用到的功能:

private func otherPublicKey(data: Data) -> SecKey? {
    var error: Unmanaged<CFError>? = nil
    
    let cfData = data.dropFirst(26) as CFData
    
    let attributes =  [
        kSecAttrKeyType: kSecAttrKeyTypeEC,
        kSecAttrKeyClass: kSecAttrKeyClassPublic,
    ] as CFDictionary
    
    if let publicKey = SecKeyCreateWithData(cfData, attributes, &error) {
        return publicKey
    }
    print("other EC public: \(String(describing: error))")
    return nil
}

private func createOwnKey() -> SecKey? {
    var error: Unmanaged<CFError>? = nil
    let keyPairAttr: [String : Any] = [kSecAttrKeySizeInBits as String: 256,
                                       kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
                                       kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false]
    ]
    guard let key = SecKeyCreateRandomKey(keyPairAttr as CFDictionary, &error) else {
        print("key creation: \(String(describing: error))")
        return nil
    }
    return key
}

此 function send僅在調試控制台上以十六進制輸出密鑰。 對於測試,可以通過復制/粘貼將其轉移到 Java 程序中。 在實際程序中,它將通過網絡連接傳輸到服務器。

private func send(ownPublicKey: SecKey) {
    guard let data = SecKeyCopyExternalRepresentation(ownPublicKey, nil) as Data? else {
        print("SecKeyCopyExternalRepresentation failed")
        return
    }
    let secp256r1Header = "3059301306072a8648ce3d020106082a8648ce3d030107034200"
    let pkWithHeader = secp256r1Header + data.hexadecimal
    print("ownPublicKeyHexWithHeader \(pkWithHeader.count / 2) bytes: " + pkWithHeader)
}

使用自己的私鑰和服務器的公鑰,可以計算共享秘密。

private func computeSharedSecret(ownPrivateKey: SecKey, otherPublicKey: SecKey) -> Data? {
    let algorithm:SecKeyAlgorithm = SecKeyAlgorithm.ecdhKeyExchangeStandard
    let params = [SecKeyKeyExchangeParameter.requestedSize.rawValue: 32, SecKeyKeyExchangeParameter.sharedInfo.rawValue: Data()] as [String: Any]
    
    var error: Unmanaged<CFError>? = nil
    if let sharedSecret: Data = SecKeyCopyKeyExchangeResult(ownPrivateKey, algorithm, otherPublicKey, params as CFDictionary, &error) as Data? {
        return sharedSecret
    } else {
        print("key exchange: \(String(describing: error))")
    }
    return nil
}

測試

在上方區域您可以看到 Xcode 控制台,在下方區域可以看到 Java 程序的 output。 共同的秘密是相同的。 所以測試成功了。

測試 ECDH Java/Swift

暫無
暫無

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

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