opensslで公開鍵暗号方式を使ってみる

Web上にバイナリデータを置きたいのだが、ただノホホンと置いておくと悪い人達に改ざんされてしまう恐れもあるので、公開鍵暗号を使って署名をつけることにした。今まで、やったことがないので、ちょっと調べてみたが、Linux(今回はUbuntuを使う)で使える公開鍵暗号方式が幾つかあった。

最初にgpgを使おうとしたが、これはメールでの利用が前提となっているみたいで、特定の相手に対して暗号したりする機能しかなかった。また、秘密鍵では暗号化できないみたい。(それほど深く調べたわけではないが。)メールの暗号化や署名には便利そうだが。

そこで、次にopensslを調べてみた。これはWebサーバとブラウザの間で暗号通信するために作らているしくみだが、Webサーバ無しでも単体で使えるし、署名目的で秘密鍵での暗号も出来る。ただし、鍵の長さにもよるが暗号化できるデータの長さが数十文字しか出来なかった。他に方法があるのかも知れないが、今回は署名目的なので十分だ。

opensslをインストールする

Ubuntu Desktopなどには標準でインストールされているが、Ubuntu Serverではインストールされていない場合もあるので、コマンドが無ければ最初にインストールする。

$ sudo apt-get install openssl

秘密鍵と公開鍵を作る

まずは鍵をつくらないといけない。誰にも教えてあげない秘密鍵、と、みんなに教える公開鍵。
秘密鍵の作り方:

$ openssl genrsa -out adsaria_private.pem -aes256 2048

この例では、“adsaria_private.pem”というファイルに2048ビット長の秘密鍵を生成する。秘密鍵なので、他の人には知られないように aes256という方法で暗号化しておく。(従って、この秘密鍵を使う時は必ずパスワードを聞かれる。)

公開鍵の作り方:

$ openssl rsa -in adsaria_private.pem -pubout -out adsaria_public.pem

先程作った秘密鍵のペアとなる公開鍵を“adsaria_public.pem”というファイルに生成する。
以下は実際に秘密鍵と公開鍵を作った例である。

 adsaria@ubuntu:~/tmp$ openssl genrsa -out adsaria_private.pem -aes256 2048
 Generating RSA private key, 2048 bit long modulus
 ..........................+++
 ............+++
 e is 12345 (0x12345)
 Enter pass phrase for adsaria_private.pem: password
 Verifying - Enter pass phrase for adsaria_private.pem: password
 adsaria@ubuntu:~/tmp$ 
 
 adsaria@ubuntu:~/tmp$ ls
 adsaria_private.pem
 adsaria@ubuntu:~/tmp$ 
 
 adsaria@ubuntu:~/tmp$ cat adsaria_private.pem
 -----BEGIN RSA PRIVATE KEY-----
 Proc-Type: 4,ENCRYPTED
 DEK-Info: AES-256-CBC,78BAE587D284CE7CDF97E8AFE6740086 

 9zeZ5AJYlbuZdXyb3tfPWDHviooh237/9/IP9zImGds2HGqvbCtcnSRuGw66e7qu
 XKUG/qyKJy+sD5Rug06YIkLlTifrH+auGdbl4ZBw4cTH3s9I4TUALAd8v0CURDiM
 z8r8TAYh/aF8Ui9rWiEtcAblMklyb1QlEIRtO4WSkTebcsosZjCOx5z14c76vZCq
 	:
 	中略
 	:
 ofESmlnYlNwL8IcT8/zHU11Xe+HY3r5Bi1nnHUX0rkXd4JZW1UAuCvj9hoXPgpB2
 kKdnL5oUrphAGBWoSVK3QNHwC1vqheA7SqDNCDbSeOkPbv+4p9mX/j0InIVG3xOl
 HAbnR/scuNQTdKOYnBA/HU2JRm/bdoIGScZ5zn/7Gxj/C6afK4OK0oaP2m6IvXKV
 -----END RSA PRIVATE KEY-----
 adsaria@ubuntu:~/tmp$  

 adsaria@ubuntu:~/tmp$ openssl rsa -in adsaria_private.pem -pubout -out adsaria_public.pem
 Enter pass phrase for adsaria_private.pem: password
 writing RSA key
 adsaria@ubuntu:~/tmp$  

 adsaria@ubuntu:~/tmp$ ls
 adsaria_private.pem  adsaria_public.pem
 adsaria@ubuntu:~/tmp$ 

 adsaria@ubuntu:~/tmp$ cat adsaria_public.pem
 -----BEGIN PUBLIC KEY-----
 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw7n3Oo1qekaWhnD5GRuj
 bv/mB1/J/brdf3K0HKARGdph1mPmYDUNr/y+4meHvfqyAMpe/eK2O20F19N7EFxx
 PicCG1LxKB6v9LZCQlvRRixEEQokN+2Xv+xv07m4iWPZNPWmZXrngoP8eeBfAuNF
 oS5UtBCVY/t6sTsleLZbvGIoadCXZryDm1UepmW44DRMj1Em5Oncn2LL98f2wGRA
 zBB9vm63jtEAB+0Jr3C0GvAypmck5e5wgQ2TepJ6MhO9Y1oeieTguYL41uEuh8/j
 W8B+EC0v2Vtmkx1+elOBnwx+w/Iw9GHTotYkhetOunKsSOB0Qev/CqrQZ6CVzmh1
 owIDAQAB
 -----END PUBLIC KEY-----
 adsaria@ubuntu:~/tmp$ 

応用例1:メールアドレスを暗号化して送る

先ずは公開鍵暗号方式の基本である、公開鍵で暗号化してデータを送り、秘密鍵で復号する例。ここではメールを他の誰にも知られないで私に送る例。

まず、私の公開鍵で暗号化する:

$ echo "name@address" | openssl rsautl -encrypt -pubin -inkey adsaria_public.pem | base64 > address.cry

$ cat address.cry 
wbxEvimBRSXehlhKCpuoSzSbxItWVsFmIsWtaQAH2OfYWKCePilpfXf8IeV8x7N9/mX5JJhd5aU2
WRsjrWwZRRp2PBm6mi4GPd47Q73mwVvelEKZHgTS15n0PQ3DzAJoohFadJheF5HLcjvZ8Jc+fam1
1iq67rrmTfIQ+OxzQrYqCvd2RluRbgCZUYslfGIH8bIizy7ezQvKFxDoDuuza2+SDxnThhZnfA9N
Or9SFaoMnA75nQsTMvKO9HFuSVdTIQTJo7IXbnsFF/M2G87TwvLy9Llyca4aipZY5mB+UQLPVkth
9eR3W08BciZuepu9bUFx5NJ4MQUjrsHT5MoJPw==

(opensslで生成する暗号ファイルはバイナリなのでここではbase64でASCIIデータに直している。)
このaddress.cryというファイルを送ってもらい、私の秘密鍵で復号する。

$ base64 -d address.cry | openssl rsautl -decrypt -inkey adsaria_private.pem
Enter pass phrase for adsaria_private.pem: password
name@address

応用例2:ファイルに署名する(秘密鍵で暗号化する)

秘密鍵で暗号化する場合は“-encrypt”ではなく“-sign”を使う。まず、改ざんされては困るファイルのハッシュ値をmd5sumで計算して、それに対して暗号化する。

$ md5sum important
295402db735cb1096b0ad784f41d5819  important
$ md5sum important | cut -f1 -d" " | openssl rsautl -sign -inkey adsaria_private.pem | base64 > important.sig
Enter pass phrase for adsaria_private.pem: password

$ cat important.sig 
EIjSHr/oNLgG0PZa7DhfIn6O0TiMhk6sg53PIDa8Kjxc+vEW+R2Y0BAoB9Ew9+4P0SrYYM04haiR
XQOX4NEK1pJ45c17DpzEClFh9K3gzhD4HRhGprKlQugib428L6i4SFQk791mj7R+LLmRBXAJ0+9x
hTF9pUchB3oa2aGMtMVMeCEGH4EFPZN5GGPUty3TU8hGnHIwJHBW2fRcFhoitWVPC7XoYZhKkCEd
yh5UXNYWqDeE0VSvZr3BLFpk2Rgjy8Qcn41nvQkD11WbbO3nTwQUCvSc2cdrgjhDJEkbV7MqbYTl
FbTg96wvu24SzyAMLCvTppWJtVH6jX7Y+Eg4/w==

ここでは大切なファイルを“important”とし、そのファイルに対する署名を“important.sig”として生成している。この2つを送って、受け取った人は署名ファイルを私の公開鍵で復号する。その場合は“-decrypt”ではなく、“-verify”を使う。

$ base64 -d important.sig | openssl rsautl -verify -pubin -inkey adsaria_public.pem 
295402db735cb1096b0ad784f41d5819

これは“画像データとしてプログラムを保存する”といった使い方に応用できる。