サーバーサイドから公開鍵をPem形式でもらったのですが、クライアントサイドで暗号化しようとすると CryptographicExceptionがスローされてしまう事態に。解決に時間を要したのでメモとして書き残しておきます。
.Net Frameworkを使ったRSA暗号化
公開鍵を使って暗号化する場合はRSAを使うのでRSACryptoServiceProviderを使用します。当時はPem形式の取り扱いが全然分からなかったので、とりあえずコンバーターサイトでXMLに変換して暗号化を試みていました。
var rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(publicKey); rsa.Encrypt(data, false);
するとRSACryptoServiceProvider.FromXmlStringメソッドがCryptographicExceptionをスローするんですね。秘密鍵だと問題がないのですが、公開鍵だとダメなんです。とても困ったのですが、当時は秘密鍵でしか暗号化しなかったのでとりあえず棚上げ。
Pemをプログラムで処理して暗号化を試みる
しかし先日公開鍵で暗号化する必要性に迫られてしまいました。以前上手くいかなかったなあ…と思いながら先日書いた方法を使ってやってみました。
www.k-karakuri.com
private string publicPemKey = "-----BEGIN PUBLIC KEY-----" + "pedjdjjdjsjajwhdjifvigkfkrjjwhqjdiock/13jfkcig..." + "-----END PUBLIC KEY-----"; public string Encrypt(string data) { var decodedPublicKey = opensslKey.DecodeOpenSSLPublicKey(publicPemKey); var provider = opensslKey.DecodeX509PublicKey(decodedPublicKey); return provider.Encrypt(Encoding.UTF8.GetByte(data), false); }
するとopensslKey.DecodeX509PublicKeyの返り値がnullになってしまいました…。なんということでしょう。原因が分かりません。
もらった公開鍵がおかしいのでは?
試しにPemからXmlに変換してくれるサイトで変換を試みると、サポートしていないフォーマットみたいなエラーが出て変換できませんでした。これはもはや公開鍵が正しくないのではないか。サーバーサイドに聞いてみました。
ssh-keygen -t rsa
すると上記コマンドでMacで出力したものと言われました。ふーむ。。そして出力内容がこれ。
ssh-rsa
Ahshdicifjfjrjidjsjahagwudogobojjsjaj1/ghjeokd...
これよく見ると-----BEGIN PUBLIC KEY-----と-----END PUBLIC KEY-----がないですね。実はこれ公開鍵ではあるのですが、これを使って.Net Frameworkは暗号化することはできません。署名された公開鍵でないとダメみたいです。
.Netは証明書の公開鍵で暗号化しないといけない
ではどうやって.Net Frameworkを使って公開鍵で暗号化するのか。それは証明書の暗号鍵を使うというのが答えです。証明書の作成には秘密鍵が必要です。サーバーサイドから秘密鍵の提供を受けて自分で自己署名するか、サーバーサイドから証明書形式か、証明書から抽出した公開鍵をもらうようにしてください。
qiita.com
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BA...
-----END PUBLIC KEY-----
確かに証明書内の公開鍵には-----BEGIN PUBLIC KEY-----と-----END PUBLIC KEY-----がありました。そして同じ秘密鍵ですが、最初にもらった公開鍵と内容が明らかに違います。この証明書内の公開鍵を使えば.Net Frameworkで暗号化できます。先に書いた2つのソースコード両方が通るようになります。
まとめ
- .Net Frameworkは署名されていない公開鍵では暗号化できない
- .Net Frameworkは署名された公開鍵(証明書)で暗号化できる