ios - 无法在 Golang 中解析来自 iOS 的 base64 DER 编码的 ASN.1 公钥

标签 ios go swift3 rsa public-key-encryption

我在 Golang 中有一个使用 RSA 加密的项目,所以现在,我有一个用于加密消息的 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)") }
})

最佳答案

我们可以转储 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 key ,没有任何算法信息。这让 Go 非常不高兴,因为它无法知道它是什么类型的 key 。参见 more about correctly exporting the key here

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

如果您无法更改 key 导出代码,您可以改为直接在 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)
}

打印出来:

key: {N:+102767083290202280873554060983826675083148443795791447833515664566475334389364583758312108980110921996262487865832851258326049062353432991986398760705560379825908169063986770245967781444794847106351934016144540466696422397564949226710181429429140226472206572796987719088983654589217713611861345869296293449649 E:65537}

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

关于ios - 无法在 Golang 中解析来自 iOS 的 base64 DER 编码的 ASN.1 公钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48761010/

相关文章:

ios - 存档验证错误 NSSetM

iphone - Collection View 中的单元格不可见

function - 如何将 time.Duration 类型传递给 go 函数?

ios - Swift3 中的 "Cannot convert value of type"错误

ios - 透明的 UITableViewHeaderFooterView

ios - 如何在WKWebView中使图像集全屏显示

string - 如何检查附加 slice 是否等于字符串?

testing - 如何在进行测试时抑制 [no test files] 消息

iOS - 在 ImageView 上点击手势问题

ios - Swift 3 函数命名约定