Karakuri.com

ベンチャー企業で働くソフトウェアエンジニアの技術録

C#や.Net Frameworkは署名されていない公開鍵を使ってRSA暗号化することはできない。証明書の用意が必要

スポンサーリンク

サーバーサイドから公開鍵を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は署名された公開鍵(証明書)で暗号化できる