【问题标题】:Could not parse base64 DER-encoded ASN.1 public key from iOS in Golang无法在 Golang 中解析来自 iOS 的 base64 DER 编码的 ASN.1 公钥
【发布时间】:2018-02-13 06:50:06
【问题描述】:

我有一个使用 RSA 加密的 Golang 项目,所以现在,我有一个用于加密消息的 Base64 公钥格式,

我使用了这个代码:

publicKeyBase64 = "MIGJAoGBAJJYXgBem1scLKPEjwKrW8+ci3B/YNN3aY2DJ3lc5e2wNc0SmFikDpow1TdYcKl2wdrXX7sMRsyjTk15IECMezyHzaJGQ9TinnkQixJ+YnlNdLC04TNWOg13plyahIXBforYAjYl2wVIA8Yma2bEQFhmAFkEX1A/Q1dIKy6EfQ+xAgMBAAE="
publicKeyBinary, err := base64.StdEncoding.DecodeString(publicKeyBase64)

publicKeyInterface, err := x509.ParsePKIXPublicKey(publicKeyBinary)
    if err != nil {
    fmt.Println("Could not parse DER encoded public key (encryption key)")
    return "","",err
}

publicKey, isRSAPublicKey := publicKeyInterface.(*rsa.PublicKey)
if !isRSAPublicKey {
    fmt.Println("Public key parsed is not an RSA public key")
    return "","",err
}

encryptedMessage, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, "message")

当我运行这段代码时,我得到了这个错误:

Could not parse DER encoded public key (encryption key)

asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:129 isCompound:false}) {optional:false explicit:false application:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier @3

错误指向publicKeyInterface,它无法从Base64解码格式解析为公钥,我的代码有什么问题?

=======更新=====

我的 publicKeyBase64 是从我的二进制数据类型的模型中检索到的

当我从我的 Rails API 将它存储在我的 mongoDB 中时,我收到了 Base64 格式的 public_key 参数,但我将它解码为二进制,然后我用这个代码存储它

def create
  params = device_params      
  public_key = Base64.decode64 device_params[:public_key]
  #device_params[:public_key] value is "MIGJAoGBAJJYXgBem1scLKPEjwKrW8+ci3B/YNN3aY2DJ3lc5e2wNc0SmFikDpow1TdYcKl2wdrXX7sMRsyjTk15IECMezyHzaJGQ9TinnkQixJ+YnlNdLC04TNWOg13plyahIXBforYAjYl2wVIA8Yma2bEQFhmAFkEX1A/Q1dIKy6EfQ+xAgMBAAE="
  params[:public_key] = BSON::Binary.new(public_key, :generic)
  device = Device.find_or_create_by(id: device_params[:id])

  render_success device.update_attributes(params), device
end

当我使用 Rails 代码使用此代码转换我的 Base64 公钥字符串时,它成功了:

rsa_public_key = OpenSSL::PKey::RSA.new(Base64.decode64(public_key))

在我的 iOS 应用程序中,我使用 https://github.com/DigitalLeaves/AsymmetricCrypto 使用此代码生成公钥:

AsymmetricCryptoManager.sharedInstance.createSecureKeyPair({ (success, error) -> Void in
   if success {
    print("RSA-1024 keypair successfully generated.")
    let publicKey = AsymmetricCryptoManager.sharedInstance.getPublicKeyData()?.base64EncodedString()

    let url = ENV.BASE_URL + "devices"
    let headers = ["Authentication-Token": CurrentUser.getCurrentUser().token] as! HTTPHeaders
    let params = ["device[user_id]": CurrentUser.getCurrentUser().id!, "device[id]": instanceID,"device[token]": fcmToken, "device[os]": "ios", "device[public_key]": publicKey!]

    Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: headers)
} else { print("An error happened while generating a keypair: \(error)") }
})

【问题讨论】:

  • 你能展示生成base64密钥的代码吗?
  • 我从我的模型中检索到它实际上是二进制数据数据类型publicKeyBase64 := base64.StdEncoding.EncodeToString(publicKey.Data)
  • 什么是Data?这不是rsa.PublicKey 的字段。
  • 它来自我的结构 PublicKey bson.Binary
  • 好吧,这仍然没有帮助。它最初来自哪里?是 pem 块中的 block.Bytes 吗?如果不是,您可能存储了错误的东西,或者试图以错误的方式对其进行解码。现在,我们只知道它是 base64。

标签: ios go swift3 rsa public-key-encryption


【解决方案1】:

我们可以转储 ASN.1 内容以查看它们的样子:

$ echo "MIGJAoGBAJJYXgBem1scLKPEjwKrW8+ci3B/YNN3aY2DJ3lc5e2wNc0SmFikDpow1TdYcKl2wdrXX7sMRsyjTk15IECMezyHzaJGQ9TinnkQixJ+YnlNdLC04TNWOg13plyahIXBforYAjYl2wVIA8Yma2bEQFhmAFkEX1A/Q1dIKy6EfQ+xAgMBAAE=" | \
    base64 -d | \
    dumpasn1 -
  0 137: SEQUENCE {
  3 129:   INTEGER
       :     00 92 58 5E 00 5E 9B 5B 1C 2C A3 C4 8F 02 AB 5B
       :     CF 9C 8B 70 7F 60 D3 77 69 8D 83 27 79 5C E5 ED
       :     B0 35 CD 12 98 58 A4 0E 9A 30 D5 37 58 70 A9 76
       :     C1 DA D7 5F BB 0C 46 CC A3 4E 4D 79 20 40 8C 7B
       :     3C 87 CD A2 46 43 D4 E2 9E 79 10 8B 12 7E 62 79
       :     4D 74 B0 B4 E1 33 56 3A 0D 77 A6 5C 9A 84 85 C1
       :     7E 8A D8 02 36 25 DB 05 48 03 C6 26 6B 66 C4 40
       :     58 66 00 59 04 5F 50 3F 43 57 48 2B 2E 84 7D 0F
       :     B1
135   3:   INTEGER 65537
       :   }

0 warnings, 0 errors.

格式良好的 ASN.1 公钥也应包含算法。我们应该有类似这样的一行:

  5   9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)

AsymmetricCryptoManager.getPublicKeyData() 返回一个非常简单的ASN.1 键,没有任何算法信息。这让 Go 非常不高兴,因为它无法知道它是什么类型的密钥。见more about correctly exporting the key here

如果您可以更改 iOS 代码,您应该改用 CryptoExportImportManager 并使用 exportPublicKeyToPEMexportPublicKeyToDER 之一。这些获取getPublicKeyData 的输出并生成可供其他工具使用的输出。您可以在CryptoExportImportManager example 中找到如何使用它们的示例。

如果您无法更改密钥导出代码,您可以直接在 Go 中解析它。这假设您确定它是 RSA 公钥:

func main() {
    publicKeyBase64 := "MIGJAoGBAJJYXgBem1scLKPEjwKrW8+ci3B/YNN3aY2DJ3lc5e2wNc0SmFikDpow1TdYcKl2wdrXX7sMRsyjTk15IECMezyHzaJGQ9TinnkQixJ+YnlNdLC04TNWOg13plyahIXBforYAjYl2wVIA8Yma2bEQFhmAFkEX1A/Q1dIKy6EfQ+xAgMBAAE="

    // Base64 decode.
    publicKeyBinary, err := base64.StdEncoding.DecodeString(publicKeyBase64)
    if err != nil {
        panic(err)
    }

    // rsa.PublicKey is a big.Int (N: modulus) and an integer (E: exponent).
    var pubKey rsa.PublicKey
    if rest, err := asn1.Unmarshal(publicKeyBinary, &pubKey); err != nil {
        panic(err)
    } else if len(rest) != 0 {
        panic("rest is not nil")
    }

    fmt.Printf("key: %+v\n", pubKey)
}

打印出来:

键: {N:+102767083290202280873554060983826675083148443795791447833515664566475334389364583758312108980110921996262487865832851258326049062353432991986398760705560379825908169063986770245967781444794847106351934016144540466696422397564949226710181429429140226472206572796987719088983654589217713611861345869296293449649 E:65537}

您现在可以在包 rsa 函数中使用您的公钥。

【讨论】:

  • 我使用了我朋友的另一个 Base64 编码(来自 android,但还不知道他现在使用的是什么库),它适用于当前代码 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkx9h4KXOoW+2Kb06pLz7vo3GN3iGqWk8sS2SxvRSM+/S6bmhrt2Mw+StSSzQSn4YMhF1rEU7fED1buI85bx8QpFwdAu1MzB1uWVXSo/koM3voAzghQTiCvoJigxgIHtKdr2e03D9vWYQPxh862yFIstzItCgksliSwLXD5++IKQIDAQAB"
  • 我认为最好更改我的 iOS 代码以发送具有 Base64 编码格式的有效公钥
  • 您朋友的密钥包括算法:echo ... | base64 -d | dumpasn1 - 显示.... OBJECT IDENTIFIER rsaEncryption ...。你的没有,只是整数。
  • 我同意,如果您可以更改 iOS 代码,那将更加耐用。其他库/工具会遇到与 Go 相同的问题。如果你想允许 EC 密钥也很好。
  • 我想,我更喜欢修复AsymmetricCryptoManager.swift中的AsymmetricCryptoManager.getPublicKeyData()来添加算法信息,但我仍然对如何添加它感到困惑。我已将 kAsymmetricCryptoManagerKeySize 的默认值从 2048 更改为 1024(因为我只需要 1024)
猜你喜欢
  • 2010-11-19
  • 2022-01-22
  • 2013-07-20
  • 2015-12-10
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
相关资源
最近更新 更多