🍀

OpenSSLでRSASSA-PKCS-v1_5 (SHA-512) を使ったRSA署名を試す

2024/10/14に公開

概要

APIのクライアント認証のため、公開鍵&秘密鍵を生成する機会がありました。

RSASSA-PKCS-v1_5とかSHA-512とか理解が曖昧なワードがたくさん出てきたので、整理のためにこの記事を書きました。

用語の整理

RSAとは

  • RSA(Rivest-Shamir-Adleman)は、公開鍵と秘密鍵のペアを利用する公開鍵暗号アルゴリズム
  • RSAを使うことで、暗号化(Encryption)と署名(Signing)を実現できる

RSASSA-PKCS-v1_5とは

  • RSASSA-PKCS-v1_5は、RSAを用いて署名をするための具体的な方法(署名スキーム)の1つ
  • RSAで署名を行う際の具体的な手順が決められている。メッセージハッシュの生成、エンコード、パディング方法など。
  • RFC 8017 - PKCS#1:RSA暗号化仕様バージョン2.2 RSASSA-PKCS-v1_5で規格が定義されている

SHA-512とは

  • Secure Hash Algorithm 512ビット
  • RSASSA-PKCS-v1_5スキームの中で利用可能なハッシュ関数の1つ
  • RSASSA-PKCS-v1_5スキームでは、ハッシュ関数としてSHA-256やSHA-1やMD5なども利用可能(※SHA-1やMD5は現在非推奨)

RSASSA-PKCS-v1_5 using SHA-512を用いたAPIクライアント認証の流れ

RSASSA-PKCS-v1_5 using SHA-512の方式は、電子証明書、API認証など幅広い用途で使用されています。

ここでは、この方式を用いたAPIクライアント認証の大まかな流れを見ていきます。

  1. 【クライアント】メッセージのハッシュをSHA-512で計算する
  2. 【クライアント】1で生成したハッシュを対象に、秘密鍵を使ってRSA署名を行う
  3. 【クライアント】2で生成した署名をリクエストに付与して、APIリクエストを行う
  4. 【APIプロバイダ】3のリクエストを受信し、公開鍵を使って、署名されたハッシュを検証する。
    ※ この検証によって、クライアントの正当性(クライアントが秘密鍵を所有していること)と、メッセージが改ざんされていないことを確認できる

OpenSSLでRSA署名を試してみる

RSA署名の理解を深めるため、OpenSSLを使って、鍵の生成から署名検証までの流れをやってみることにします。

RSA公開鍵と秘密鍵を生成する

OpenSSLのバージョン

これ以降の作業は、以下のバージョンで実施しました。

$ openssl version
OpenSSL 3.3.1 4 Jun 2024 (Library: OpenSSL 3.3.1 4 Jun 2024)

秘密鍵の生成

まず、秘密鍵を生成します。

$ openssl genpkey -algorithm RSA -out private_key.pem

以下は、コマンドの詳細です。

  • genpkey: generate private keyの略で、秘密鍵を生成するopensslのコマンド

  • -algorithm: 鍵の生成に使用するアルゴリズムを指定する。ここではRSA。

  • -out: 生成された秘密鍵を保存するファイルの名前を指定する

https://docs.openssl.org/master/man1/openssl-genpkey/

これにより、private_key.pemという名前で秘密鍵が生成されます。

private_key.pem
-----BEGIN PRIVATE KEY-----
...略
-----END PRIVATE KEY-----

秘密鍵に対応する公開鍵を作成する

次に、公開鍵を生成します。

以下のコマンドを使用して、秘密鍵に対応する公開鍵を生成します。

$ openssl rsa -pubout -in private_key.pem -out public_key.pem
writing RSA key

以下は、コマンドの詳細です。

  • rsa -pubout: -puboutを指定すると、公開鍵を生成する

  • -in: RSA秘密鍵を指定する

  • -out: 生成された公開鍵を保存するファイルの名前を指定する

コマンド実行後、public_key.pemという名前で公開鍵が生成されます。

public_key.pem
-----BEGIN PUBLIC KEY-----
...略
-----END PUBLIC KEY-----

OpenSSLでRSA署名をする

次に、生成した鍵を使って実際にデータの署名を行います。

署名するデータを準備し、このデータに対してRSA署名を行います。ここでは、message.txtというテキストファイルに対して署名を実行します。

$ openssl dgst -sha512 -sign certs/private_key.pem -out projects/signtest/signature.bin projects/signtest/message.txt

以下は、コマンドの詳細です。

  • dgst: メッセージのダイジェスト(ハッシュ値)を生成するOpenSSLコマンド
  • -sha512: ハッシュアルゴリズムとしてSHA-512を指定する
  • -sign: 指定した秘密鍵でデータを署名する
  • -out: 署名結果を保存するファイル名(signature.bin)を指定する
  • message.txt: 署名対象となるテキストファイルを指定する

これにより、signature.binというファイルが生成されます。

このファイルには、秘密鍵を元に生成したデジタル署名が含まれます。この署名signature.binと対象データを検証することで、データが改ざんされていないことや正当な送信者によって署名されたことを確認できます。

APIクライアント認証における署名

APIクライアント認証の場合、署名はAPIを利用するアプリケーション(クライアント)で実行されます。クライアントは、秘密鍵を使って、リクエストに署名を付与し、APIプロバイダに送信します。

OpenSSLでRSA署名の検証をする

さて、最後に署名を検証を行います。これは、データ受信側がそのデータの正当性を確認するプロセスです。

署名検証には下記コマンドを入力します。

$ openssl dgst -sha512 -verify certs/public_key.pem -signature projects/signtest/signature.bin projects/signtest/message.txt
Verified OK

以下は、コマンドの詳細です。

  • -verify: 公開鍵を使って署名を検証
  • -signature: 署名ファイルを指定する
  • message.txt: 元のメッセージファイルを指定する

コマンドを実行すると、Verified OKになっています。

これは、署名検証により、

  • 秘密鍵を保持する正しいクライアントにより署名されたこと
  • message.txtのデータが改ざんされていないこと

が確認されたことを意味します。

APIクライアント認証における署名検証

APIクライアント認証の場合、署名検証はAPIプロバイダ側で実施します。APIプロバイダは、クライアントからリクエストに付与されて送信された署名を検証します。

検証結果が不正となる例

署名検証の結果、不正になる例も見てみましょう。

署名後にmessage.txtを変更して、検証の結果が不正であることを確認します。

$ openssl dgst -sha512 -verify certs/public_key.pem -signature projects/signtest/signature.bin projects/signtest/message.txt
Verification failure
000C70EF01000000:error:02000068:rsa routines:ossl_rsa_verify:bad signature:crypto/rsa/rsa_sign.c:426:
000C70EF01000000:error:1C880004:Provider routines:rsa_verify:RSA lib:providers/implementations/signature/rsa_sig.c:785:

今度は署名が不正という結果になりました。これは、署名後にmessage.txtを変更したため、元のデータと異なることが検出されたということです。

最後に

急にRSA鍵の生成と公開鍵の提供を求められ、「???」となったため、付け焼き刃ながら勉強したことを書きました。

冒頭にも書きましたが、より専門的な内容は然るべきドキュメント等を当たってくださいますようお願いいたします。

Discussion