# 電子署名 (overview)

## 説明

### 電子署名とは

電子署名とは、インターネットなどの信頼できない経路から送られてきたデータが、正当なものであることを証明するための機構です。

- 作業主体として署名する人（開発者）・検証する人（ユーザのDS）が関与します。
- データとしては、秘密鍵・公開鍵・送信データ・送信データに対する電子署名、が介在します。
- 秘密鍵は署名する人だけが知っており、秘密にしています。
- 公開鍵は、何らかの信頼できる手段（ゲームカードに焼きこまれている）により、検証する人が前もって入手しているものとします。
- 送信データは任意のサイズのバイナリファイルです。

1. まず、署名する人が秘密鍵を使用して、送信データから固定長の電子署名を作成します。
   （実際には、送信データのハッシュ値を取り、それに対して操作を行います。）
2. その後、検証する人が、送信データとそのデータへの電子署名をインターネットなどを経由して受け取ります。
3. 検証する人は、あらかじめ入手していた公開鍵の情報だけを用いて、 送信データとその署名から、データが正当なものであることを検証できます。

電子署名という機構の特徴は以下のようになります。

- 公開鍵さえ事前に知っていれば、外部との通信を行わずに、データとそれへの署名だけを用いて正当性を判定できる。
- 公開鍵が明らかになっても、秘密鍵さえ漏洩しなければ、署名の偽造ができない。
  （すなわち、DS 側の ROM バイナリが万が一解析されたとしても、署名の偽造ができない。）

### CRYPTO ライブラリが提供する電子署名機能

TwlSDKのCRYPTOライブラリでは、Nitro-Cryptoの時から存在する電子署名検証機能の他に 電子署名作成機能も追加しました。

電子署名検証機能としては `CRYPTO_VerifySignature()` および `CRYPTO_VerifySignatureWithHash()` で提供しています。 証明書の有効期限管理などの機能はありません。 必要に応じてアプリケーション側で実装して下さい。

電子署名作成機能としては `CRYPTO_RSA_Sign()` を提供しています。 この関数は単独で実行しても処理できません。 この関数を実行する前に `CRYPTO_RSA_SignInit()` で初期化を行い、署名作成実行後に `CRYPTO_RSA_SignTerminate()` で終了処理を行う必要があります。

また、電子署名はデータの正当性の検証を行うだけの仕組みですので、データの暗号化は行いません。
CRYPTOライブラリでは、暗号強度に劣るものの処理が高速なRC4・より暗号強度が高い共通鍵暗号方式のAES・鍵配送の点で有利な公開鍵暗号のRSAという3つの暗号化方式を用意してあります。 RC4 アルゴリズムに関しては RC4 アルゴリズム概要 を、RSA アルゴリズムに関しては RSA アルゴリズム概要 を参照してください。
また、TwlSDKではハードウェア機能を用いたAES暗号化機能も用意しています。詳しくはAESの項目をご覧下さい。

なお、電子署名検証機能はNITRO/TWL共に動作しますが、電子署名作成機能はライセンスの都合上TWLのみで動作します。

### 署名データの形式

`CRYPTO_VerifySignature*` に渡す署名データ及び鍵は以下の条件を満たしていれば どのような方法で生成しても構いません。 (もちろん `CRYPTO_RSA_Sign()` で作成した署名データも利用できます)

- 鍵のデータフォーマットがASN.1形式に準拠しており、DERエンコードされている
- ハッシュアルゴリズムには SHA-1 を使用している
- 公開鍵暗号のアルゴリズムには RSA を使用し、鍵長は 1024bit である
- 使用している公開鍵の公開指数が 65537 である

### 署名データの作成例

一例として、オープンソースの SSL ツールキットである OpenSSL で電子署名を作成する手順を以下に述べます。

1. 署名用の RSA 鍵を生成する

OpenSSL がインストールされている環境のコマンドラインで、以下のコマンドを入力することで、 鍵長 1024 bit の RSA 鍵ファイル privkey.pem を作成します。

     > openssl genrsa -out privkey.pem 1024

万が一、privkey.pem が漏洩すると、誰もが署名できるようになってしまいます。 秘密鍵の鍵ファイルは厳重に取り扱うようにしてください。

鍵の作成時に暗号化方式を指定することで、privkey.pem にパスワードによる暗号化を行うことも可能です。 以下の例では、新規に作成した privkey.pem を 3DES アルゴリズムによって暗号化します。

     > openssl genrsa -des3 -out privkey.pem 1024

詳細は openssl のリファレンスを参照してください。

2. RSA 鍵の内容を確認する

以下のコマンドで、privkey.pem の内容を確認することができます。

     > openssl rsa -in privkey.pem -text -noout

この中には、署名を行うために必要な秘密情報が含まれていますが、 後の検証のために必要な情報（公開鍵）は modulus と publicExponent の2つの数値です。
以下はコマンドの出力から modulus と publicExponent を抜粋した例です。

    modulus:
    00:eb:95:be:33:19:73:64:f2:72:2c:87:c8:0a:f3:
    1c:ba:e0:4c:e0:3e:1d:f6:e2:09:aa:70:f0:b3:b9:
    0c:86:36:62:2d:12:13:86:fa:a5:3d:93:cb:5f:0b:
    45:64:9b:7b:eb:b5:c6:f9:42:99:70:46:f3:14:6d:
    8f:f9:b9:ec:38:30:a0:1c:28:0d:30:d9:86:1a:4d:
    1b:f2:e9:05:1b:43:06:b2:c0:55:ed:c4:bb:8e:1a:
    a5:ab:2b:54:e5:dc:8d:70:cf:af:91:94:c9:e9:8f:
    7f:9f:29:28:be:e7:01:b0:20:d4:f2:71:58:93:db:
    25:1c:26:bc:98:f3:a2:b3:47
    publicExponent: 65537 (0x10001)

`CRYPTO_VerifySignature*` で扱う公開指数は 65537 で固定ですので、 publicExponent が 65537 であることを確認してください。

modulus の数値は、以下のコマンドで出力することも可能です。

     > openssl rsa -in privkey.pem -modulus -noout

このコマンドでは以下のような文字列が出力されます。

     Modulus=EB95BE33197364F2722C87C80AF31CBAE04CE03E1DF6E209AA70F0B3B90C8636622D121386FAA53D93CB5F0B45649B7BEBB5C6F942997046F3146D8FF9B9EC3830A01C280D30D9861A4D1BF2E9051B4306B2C055EDC4BB8E1AA5AB2B54E5DC8D70CFAF9194C9E98F7F9F2928BEE701B020D4F2715893DB251C26BC98F3A2B347

この出力中の "Modulus=" の後に続く16進数を何らかの方法で C 言語の u8 の配列に変換して、`CRYPTO_VerifySignature*` に mod_ptr として渡してください。 なお、この出力例では Modulus が 127 バイトですが、このように 128 バイトより少ない場合は 先頭（上位桁）の 0 が省略されていますので、 全体が 128 バイトになるように先頭へ 0 を詰めた状態で mod_ptr に渡す必要があります。

3. 電子署名を作成する

ここまで準備ができれば、あとは任意のデータを持って来て電子署名を作成するだけです。
電子署名はTWLの場合 `CRYPTO_RSA_Sign()` を用いて作成することもできますし、PCにて作成することもできます。
以下のコマンドで、秘密鍵 privkey.pem で hoge.txt を署名した hoge.sign という署名データが作成されます。

     > openssl dgst -sha1 -sign privkey.pem -out hoge.sign hoge.txt

出来上がったファイルサイズが 128 バイトであることを確認してください。
この 128 バイトのバイナリデータを DS に転送し、sign_ptr として `CRYPTO_VerifySignature*()` に渡します。
なお、作成した署名データが正しい電子署名となっているかを PC 上で確認するには、以下のコマンドを実行します。

     > openssl dgst -sha1 -prverify privkey.pem -signature hoge.sign hoge.txt

4. 電子署名を検証する

DS のプログラムに予め公開鍵データを埋め込んでおき、そこへ、通信などの何らかの手段でデータ本体とその電子署名データを送ります。 `CRYPTO_VerifySignature*` に対して、そのデータ本体とサイズ、電子署名データ(128バイト)と、 埋め込まれた公開鍵データ(128バイトのmodulus)を与えることにより、電子署名を検証し、正当なものと認められれば関数は TRUE を返します。

## 参照

`CRYPTO関数一覧
`

## 履歴

2008/10/02 鍵のフォーマットに関する修正
2008/09/16 コメントの一部修正
2008/04/18 電子署名作成機能追加に対応
2008/03/27 TwlSDK移植版 初版
2006/03/07 初版 (NitroCrypto)