暇を見つけては社内で使うちょっとしたWebアプリケーションの開発を進めているのですが、その中でクライアント(JavaScript)-サーバ(Perl)間での暗号化・復号を行う仕組みが必要となったため公開鍵暗号方式のRSAによる実装にトライしてみました。
やりたいことの流れはこんな感じ。
- サーバ(Perl)側でRSA鍵(秘密鍵・公開鍵)を生成
- 公開鍵をクライアント(JavaScript)に渡す
- クライアント(JavaScript)側で公開鍵を用いて暗号化
- 暗号化された文字列をサーバ(Perl)に返す
- サーバ(Perl)側で秘密鍵を用いて復号
色々なモジュールを試してみたのですが、RSAといっても種類が色々あるようで(?)組み合わせによっては元の文字列を上手く復元出来ないケースもあり難儀しましたが、最終的にJavaScript側で「JSEncrypt」、Perl側は「Crypt::OpenSSL::RSA」を利用することで上手く行きました。
実装例
まずはサーバ(Perl)側でRSA鍵(秘密鍵・公開鍵)を生成します。
use strict;
use Crypt::OpenSSL::RSA;
my $rsa = Crypt::OpenSSL::RSA->generate_key(1024);
# 秘密鍵
print $rsa->get_private_key_string();
# 公開鍵
print $rsa->get_public_key_x509_string();
公開鍵をクライアント(JavaScript)側に渡したら、JSEncryptを用いて暗号化。
<script src="jsencrypt.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
var pubkey = '(公開鍵)';
var passwd = '(暗号化したい文字列)';
var enc = new JSEncrypt();
enc.setPublicKey(pubkey);
var cipher = enc.encrypt(passwd);
alert(cipher);
});
</script>
JSEncryptで生成した暗号化文字列を受け取ったサーバ(Perl)側は先に発行しておいた秘密鍵で復号化します。JSEncryptで暗号化した文字列はBase64でエンコードされているので先にデコードしておく必要があります。
use strict;
use Crypt::OpenSSL::RSA;
use MIME::Base64;
my $text = '(暗号化された文字列)';
my $private_key = '(秘密鍵)';
my $rsa = Crypt::OpenSSL::RSA->new_private_key($private_key);
$rsa->use_pkcs1_padding;
print $rsa->decrypt(decode_base64($text));
以上