OpenSSL::PKey::RSAクラスを利用してRSA暗号の秘密鍵と公開鍵の作成方法について、今回は以下の2つの方法を紹介します。
- 乱数を利用する方法
- 事前に用意した秘密鍵を読み込ませる方法
乱数を利用する方法
OpenSSL::PKey::RSAのgenerateメソッドを利用すると乱数から秘密鍵と公開鍵のペアが生成できます。メソッドの戻り値はRSAオブジェクトです。
乱数が適切に初期化されている必要があるため、generate
の前にOpenSSL::Randomを実行する必要があります。
鍵のサイズ(ビット数)はgenerate
の引数で指定します。サイズは1024以上が推奨されています。1
具体的な実行手順は以下の通りです。
$ irb
### OpenSSLを利用できるようにする
> require 'openssl'
=> true
### /dev/randomを利用して乱数を初期化する
> OpenSSL::Random.seed(File.read("/dev/random", 16))
=> "\x84\\.\x9D\x8EX\xE4\x9D\xBE\x94[T\xE1\xB2m\x92"
### RSAオブジェクト(RSA秘密鍵)の生成
> rsa_private = OpenSSL::PKey::RSA.generate(2048)
=> #<OpenSSL::PKey::RSA:0x00007fea4d059940>
### 秘密鍵のペアとなる公開鍵の取得
> rsa_public = rsa_private.public_key
=> #<OpenSSL::PKey::RSA:0x00007fea4d060e20>
動作確認
作成した秘密鍵と公開鍵のペアで秘密鍵と公開鍵のペアでJWTのエンコードとデコードが正しくできることを確認してみます。
なお、以下のコードを実行するには事前にjwtのインストールが必要です。
$ rails c
> OpenSSL::Random.seed(File.read("/dev/random", 16))
=> "\x84\\.\x9D\x8EX\xE4\x9D\xBE\x94[T\xE1\xB2m\x92"
> rsa_private = OpenSSL::PKey::RSA.generate(2048)
=> #<OpenSSL::PKey::RSA:0x00007f65f07cb4d0 oid=rsaEncryption>
> rsa_public = rsa_private.public_key
=> #<OpenSSL::PKey::RSA:0x00007f65f07b9050 oid=rsaEncryption>
### テストデータ(payload)の作成
> payload = { id: 1, name: 'Yamada' }
### 秘密鍵を使ってテストデータをエンコード
> token = JWT.encode(payload, rsa_private, 'RS256')
=> "eyJhbGci...(略)"
### 公開鍵を使ってテストデータをデコード
> JWT.decode(token, rsa_public, true, { algorithm: 'RS256' })
=> [{"id"=>1, "name"=>"Yamada"}, {"alg"=>"RS256"}]
### デコードは秘密鍵でもできる
> JWT.decode(token, rsa_private, true, { algorithm: 'RS256' })
=> [{"id"=>1, "name"=>"Yamada"}, {"alg"=>"RS256"}]
事前に用意した秘密鍵を読み込ませる方法
OpenSSL::PKey::RSAのnewメソッドを利用するとRSAオブジェクトが生成できます。
newメソッドの引数にはIOオブジェクトを指定できるため、事前に配置した秘密鍵をnewメソッドで読み込むと秘密鍵と公開鍵のペアが生成できます。
たとえばopenssl
コマンドで生成した秘密鍵を利用してRSAオブジェクトを作成する手順は以下の通りです。
### service.keyへ出力
# 引数で鍵のサイズを指定
$ openssl genrsa 2024 > service.key
Generating RSA private key, 2024 bit long modulus
.........+++
.................+++
e is 65537 (0x10001)
### service.key が作成される
$ ls
service.key
$ irb
### OpenSSLを利用できるようにする
> require 'openssl'
### service.keyを読み込んでRSAオブジェクト(RSA秘密鍵)を生成
> rsa_private = OpenSSL::PKey::RSA.new(File.read("service.key"))
=> #<OpenSSL::PKey::RSA:0x00007fd31e9775b8>
### 秘密鍵のペアとなる公開鍵の取得
> rsa_public = rsa_private.public_key
=> #<OpenSSL::PKey::RSA:0x00007fd31e97f8f8>
動作確認
作成した秘密鍵と公開鍵のペアでJWTのエンコードとデコードが正しくできることを確認してみます。
なお、以下のコードを実行するには事前にjwtのインストールが必要です。
JWTの概要の詳細解説はJWTの概要と構成要素(ヘッダ/ペイロード/署名)を理解する、jwt gemの詳細解説は【Ruby】jwt gemの使い方とJWTのエンコード・デコード方法の具体例で紹介しています。
### 秘密鍵を事前に生成する
$ cd /path/to/Rails/root
$ openssl genrsa 2024 > service.key
$ rails c
### Railsのルートパスにある『service.key』を読み込む
> rsa_private = OpenSSL::PKey::RSA.new(File.read(Rails.root.join('service.key')))
=> #<OpenSSL::PKey::RSA:0x00007f65f0731948 oid=rsaEncryption>
### 公開鍵の作成
> rsa_public = rsa_private.public_key
=> #<OpenSSL::PKey::RSA:0x00007f65f071f3b0 oid=rsaEncryption>
### テストデータ(payload)の作成
> payload = { id: 1, name: 'Yamada' }
### 秘密鍵を使ってテストデータをエンコード
> token = JWT.encode(payload, rsa_private, 'RS256')
=> "eyJhbGci...(略)"
### 公開鍵を使ってテストデータをデコード
> JWT.decode(token, rsa_public, true, { algorithm: 'RS256' })
=> [{"id"=>1, "name"=>"Yamada"}, {"alg"=>"RS256"}]
### デコードは秘密鍵でもできる
> JWT.decode(token, rsa_private, true, { algorithm: 'RS256' })
=> [{"id"=>1, "name"=>"Yamada"}, {"alg"=>"RS256"}]
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!