はじめに
暗号についての知識が乏しい状態でプログラムを実装していて、エラーが出たので原因と解決方法を調べました。
備忘録としてまとめます。
公開鍵とは何か?
公開鍵は、データを安全にやりとりするために使う暗号技術の一部です。
主な特徴は次のとおりです。
- 公開鍵: 誰でも使える鍵で、データを暗号化するために使います
- 秘密鍵: 公開鍵とペアになっている鍵で、暗号化されたデータを復号するために使います
たとえば、誰かに秘密のメッセージを送りたいとき、その相手の公開鍵を使って暗号化し、相手だけが持つ秘密鍵で復号する仕組みです。
問題
以下の公開鍵ファイル(SSH形式)がありました。
public_key.ssh
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD34RFfMhjKd9RtGqYPwLzxXksv4rTUHl2cVwPqK7GyhnVfN3pkWA7X89JovKQy3RTr9gXNz2QsM8xP1G6n7L4oz3WzT7CLYMKH7dkRf56JoXhR9UvAZ8wzK1YoLdVg6TPZf2kYsmXr8g3NXYr6JQu9uH6p97cKsGzXL2L5I8vTjDZnRyMH3WpYrBLoXqJZKf4W8NzvLkpM2R6PYmWFoNzLd9ZY3XaGrqLTrKVyRP9jM7Bgp9CRf7JopMqcKMYWTLn3XJw9T89WPoLDkQM7Rf39YWKsl9Xk3JPMXNv9p3ZkRuQ3KzLpRYfg5TXmQ1LvJ9PsX8DjZ7CkW3NkMJz3
これをRubyで読み込もうとすると、エラーが発生しました。
$ irb
irb(main):001> require 'openssl'
=> true
irb(main):002> public_key = OpenSSL::PKey::RSA.new(File.read('public_key.ssh'))
/Users/hogehoge/benv/versions/3.3.4/lib/ruby/3.3.0/openssl/pkey.rb:356:in `initialize': Neither PUB key nor PRIV key (OpenSSL::PKey::RSAError)
from /Users/hogehoge/.rbenv/versions/3.3.4/lib/ruby/3.3.0/openssl/pkey.rb:356:in `new'
from /Users/hogehoge/.rbenv/versions/3.3.4/lib/ruby/3.3.0/openssl/pkey.rb:356:in `new'
from (irb):2:in `<main>'
from <internal:kernel>:187:in `loop'
from /Users/hogehoge/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/irb-1.14.1/exe/irb:9:in `<top (required)>'
from /Users/hogehoge/.rbenv/versions/3.3.4/bin/irb:25:in `load'
from /Users/hogehoge/.rbenv/versions/3.3.4/bin/irb:25:in `<main>'
これは公開鍵の形式がRubyのOpenSSLライブラリに対応していなかったために起こったエラーです。
OpenSSLは暗号化に必要な機能を提供するライブラリです。
OpenSSL::PKey::RSA.new
メソッドはPEM形式もしくはDER形式のデータを受け取ることが想定されています。
解決策
エラーを解消するには、公開鍵をSSH形式からPEM形式に変換する必要があります。
SSH形式とPEM形式の違い
- SSH形式: SSH接続で使うための鍵の形式、
ssh-rsa
などの文字列が先頭に含まれています - PEM形式: OpenSSLで扱うための鍵の形式、鍵全体が
-----BEGIN RSA PUBLIC KEY-----
と-----END RSA PUBLIC KEY-----
で囲まれています
形式の変換
以下のコマンドを使うと、SSH形式の公開鍵をPEM形式に変換できます。
ssh-keygen -f public_key.ssh -e -m PEM > public_key.pem
生成されたpublic_key.pem
ファイルを使って再度読み込んでみます。
$ irb
irb(main):001> require 'openssl'
=> true
irb(main):002> public_key = OpenSSL::PKey::RSA.new(File.read('public_key.pem'))
=> #<OpenSSL::PKey::RSA:0x00000001287e8bb8 oid=rsaEncryption>
無事にオブジェクトが生成されました!
おわりに
暗号の分野には苦手意識を持っているため、少しずつ知識とアウトプットを積み重ねていきます。
参考資料