電子署名、特にXMLの。(前編)
ここしばらく電子署名まわりのコードを書いてました。 何にどう使ってるかは内緒。
電子署名
「平文と暗号文と公開鍵が分かってる」ってまずくないのかな、とか思って調べてるうちに見付けた記事。
僕も「電子署名はハッシュを秘密鍵で暗号化したものをハッシュと一緒に相手に渡して公開鍵で復号できるかどうかで検証する。」と理解してたので、?となったあと、なるほどなーという感じ。
なお、最初の疑問については、よくよく考えたら公開鍵暗号って電子署名に限らずそういうものでした。
選択平文攻撃 Chosen-plaintext attack (CPA)
任意の平文に対応する暗号文を得られる条件で、暗号文から平文を求める攻撃である。公開鍵暗号の場合には、公開鍵を用いて任意の平文を暗号化できるため、選択平文攻撃に対して安全であることが必須である。 暗号解読 - Wikipedia
GnuPG
gpg --verify
のリターンコードは検証成功時に成功の0、検証失敗時に失敗扱いになるようなので、シェルスクリプトなんかで署名が正しいかどうかなどを検証することもできる。
XML電子署名
署名を付けたいデータがXMLファイルだったので、テキストファイルとして署名を付けてもよかったのだけれど、折角なのでこっちで。学生の頃に色々研究されてた記憶がある。
- XMLとして同じなら(たとえば
<root/>
と<root></root>
とか。)、データを変更しても署名が変わらない。(署名する前に正規化などの変換をしている。) - 署名したいXMLデータ自身の中に署名を埋め込める。
- 署名部分を抜き取る仕様が決まっていて、それで署名を抜き取ったあとのデータに対して署名が正しいかどうかを検証する。
- (元データ+署名で署名付きのデータを配る方法はGPGでもできる。)
Javaが読み書きできる鍵の形式
XMLや暗号まわりについては、Javaはかなりこの辺りのライブラリが標準で充実している。
「秘密鍵と公開鍵のペア」というと、日常よく触るのはsshの鍵に使うssh-keygenとかで作るid_rsaとid_rsa.pubのペアで、
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxBgSJMzzdZ3aoBtt3Joyn3hlQr81jmRb9cK41LxZSA+U+RKKAop72dbAikCqjedbTBnEQyxT4M2OZuh/yYAPX0iV+E3MfxugBUZJkNPaqawD6kG20nj/HY8bdUWSDfoeEgNa+nelFSUeMMcHBXwqYz6mtQ1h41RrQjDPCe/ZWy0jPUlYRqvvwFvXtTPdR7VIYpVDoe9aVSpZS/nV19uxKpMO+5CTL4I2YFQFqTCv5TnPqr4kBHGzqqn+FWwk2yVd4NTfX28Rpk9XVl6bugPp97SLgDpKYugeQxiwh46VT9WpvGZVqaxiJlSUrZfVqx/YVc2JOr6NudW4P5Z5g1Yb5 kzwmsyk@spellbound.local
たとえば公開鍵がこういうのだったりするのですが、これはOpenSSH形式と呼ばれるもので、独自フォーマット。
PEMとかDERとかP7XとかPFXとか一杯あって正直困るのですが違いはこの辺にまとまってます。
- RSA公開鍵のファイル形式とfingerprint - Qiita
- What are the differences between PEM, DER, P7B/PKCS#7, PFX/PKCS#12 certificates | My Online Storage of Knowledge
- RSA鍵、証明書のファイルフォーマットについて - Qiita
余談だけど、Windowsのコード署名にはpfx形式の鍵を使う。これも最近やった。
で、そんな感じで色々有る中で、Javaのライブラリが読めるのはPKCS#8のDER形式。
OpenSSLを使ってこんな感じで作れる。最初のprivate_key.pemはRSA秘密鍵で、ssh-keygen -t rsa -b 2048
が作る秘密鍵と同じ。
秘密鍵から公開鍵を作ってるのは暗号化アルゴリズムがRSAだからできるということらしい。(逆は当然非常に難しい。)
# generate a 2048-bit RSA private key $ openssl genrsa -out private_key.pem 2048 # convert private Key to PKCS#8 format (so Java can read it) $ openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt # output public key portion in DER format (so Java can read it) $ openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der
(codeartisan: RSA Public Key Cryptography in Javaより)
次はJavaでの実装について。