获取 SecKey 的字符串表示形式

Getting a string representation of a SecKey

编辑 添加了所需请求的屏幕截图。

我正在尝试在 Swift 4 中制作 MacOs 应用程序。此应用程序与需要 RSA 加密的 api 进行通信。

Google 没有给出可以解释如何做到这一点的结果。 Apple 关于此主题的文档相当丰富 (https://developer.apple.com/library/content/documentation/Security/Conceptual/CertKeyTrustProgGuide/KeyRead.html#//apple_ref/doc/uid/TP40001358-CH222-SW2),但仍然不是我需要的。

函数 SecKeyCopyExternalRepresentation 给出了一个数据对象 不能转换为字符串。文档说这是 PCKS #1 响应,但我无法解决。

我已经尝试了很多方法,包括下面的方法,但我无法让它工作。

func externalRepresentation(_ key: SecKey) -> String? {
    var error: Unmanaged<CFError>?

    guard let data = SecKeyCopyExternalRepresentation(key, &error) as Data? else {
        return nil
    }

    return data.base64EncodedString()
}

请求需要如下: Request

这在 Swift 中甚至可能吗?

将二进制 blob(如证书或 RSA 密钥作为字符串)编码的正常方法是使用 base64 encoding. You can convert a Data to base64 quite easily with the function base64EncodedString(options:)。即

let myString = myData.base64EncodedString()

很难说这是否正是您对该应用程序所需要的,因为您的问题没有提供太多上下文。

查看您的屏幕截图以及 base64 编码字符串,您需要页眉和页脚。数据结构中的大部分明显随机字母都是 base64 字符串(JSON 转换已使用 \n 对换行符进行编码,而其他内容已将反斜杠加倍)。因此,您的最后一步是在字符串前加上 -----BEGIN PUBLIC KEY----- 和一个新行,然后追加一个新行和 -----END PUBLIC KEY-----

还有一件事:您可以使用 Data.init?((base64Encoded base64String:,options:) 很容易地从 base64 字符串中取回原始数据。即

guard let myDataCopy = Data(base64Encoded: myString)
else { fatalError("the string was not really base64") }

SecKeyCopyExternalRepresentation returns RSA 密钥的 PKCS #1 格式数据。 RSA Public 密钥 PEM 文件如下所示

-----BEGIN RSA PUBLIC KEY-----
BASE64 ENCODED DATA
-----END RSA PUBLIC KEY-----

在 base64 编码数据中存在以下 DER 结构:

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}

RSA 密钥的 PKCS #1 格式应预先添加适当的“预编码”ASN.1 二进制数据结构。参考下例中的pemPrefixBuffer:

        // creating client public and private key
        var publicKeySec, privateKeySec: SecKey?
        var error: Unmanaged<CFError>?
        let keyattribute = [
            kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
            kSecAttrKeySizeInBits as String : 1024,
            kSecAttrIsPermanent as String: false
            ] as CFDictionary
        SecKeyGeneratePair(keyattribute, &publicKeySec, &privateKeySec)
        
        // client public key to pem string
        let keyData = SecKeyCopyExternalRepresentation(publicKeySec!, &error)
        let data = keyData! as Data
        let pemPrefixBuffer :[UInt8] = [
            0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
            0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
            0x05, 0x00, 0x03, 0x81, 0x8d, 0x00
        ]
        var finalPemData = Data(bytes: pemPrefixBuffer as [UInt8], count: pemPrefixBuffer.count)
        finalPemData.append(data)
        let finalPemString = finalPemData.base64EncodedString(options: .lineLength64Characters)
        let clientPublicKeyString = "-----BEGIN PUBLIC KEY-----\r\n\(finalPemString)\r\n-----END PUBLIC KEY-----\r\n"

现在您可以将客户端PublicKeyString 发送到您的服务器,期望 PEM 编码的 RSA Public 密钥。