+ All Categories
Home > Documents > セキュリティ API に関する技術調査 ·...

セキュリティ API に関する技術調査 ·...

Date post: 22-May-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
65
15 情経第 1516 号 セキュリティ API に関する技術調査 - Part 2 - Java JCE(Java Cryptographic Extensions):機能と利用法 2004 年 2 月 独立行政法人 情報処理推進機構
Transcript
Page 1: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

15 情経第 1516 号

セキュリティ APIに関する技術調査

- Part 2 -

Java JCE(Java Cryptographic Extensions):機能と利用法

2004 年 2 月 独立行政法人 情報処理推進機構

Page 2: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

登録商標について

Microsoft、MS、Windows、Windows 2000、Windows NT、Windows ロゴ、Internet Explorer、Outlook、

Visual C++などは、米国Microsoft Corporationの米国およびその他の国における登録商標または商標

である。

Sun microsystems、Sun ロゴ、Java コーヒーカップロゴ、Solaris、Java、JDK、Slaris などは、米国 Sun

microsystemsの米国およびその他の国における登録商標または商標である。

その他、本文書に記載されている会社名、商品名、製品名などは、一般に各社の商標または登録商標

または商標である。

本書では、™、©、®などを記載しない

Page 3: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

i

― 目 次 ―

1 はじめに.................................................................................................................. 1 2 Javaのセキュリティ APIの構造 ............................................................................ 5 3 Javaのセキュリティフレームワークにおける JCE................................................ 7 4 Java JCEを利用したアプリケーション ................................................................. 9 4.1 暗号化と復号 ................................................................................................... 9 4.2 一方向性ハッシュ .......................................................................................... 17 4.3 証明書検証 ..................................................................................................... 20 4.4 電子署名の作成と検証 ................................................................................... 29 4.5 キーストアの操作 .......................................................................................... 35 5 Java JCEのプロバイダの実装.............................................................................. 48 6 まとめ ................................................................................................................... 55 7 参考文献................................................................................................................ 56 8 用語(参考) ........................................................................................................ 57

Page 4: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

ii

― 図 目 次 ―

図 2-1 SECURITYと参照するフレームワーク群...................................................................................... 6 図 4-1 EXAMPLE1コンストラクタ........................................................................................................ 10 図 4-2 JAVA.SECURITY.SPEC.KEYSPEC関連クラス/インスタンス関連図 .............................................. 13 図 4-3 EXAMPLE1 DOENCRYPTION()メソッド ....................................................................................... 14 図 4-4 EXAMPLE1 DODECRYPTION()メソッド ....................................................................................... 15 図 4-5 EXAMPLE1 DOPROCESS()メソッド ............................................................................................. 16 図 4-6 EXAMPLE2クラスのコンストラクタ ......................................................................................... 18 図 4-7 EXAMPLE2.RUN()メソッド ......................................................................................................... 20 図 4-8 EXAMPLE3コンストラクタ........................................................................................................ 24 図 4-9 EXAMPLE3 LOADCERTIFICTATE.................................................................................................. 26 図 4-10 EXAMPLE3 STATIC初期化子 ..................................................................................................... 26 図 4-11 クラス/インスタンス関連図 .................................................................................................... 27 図 4-12 リポジトリィ設定のサンプルコード....................................................................................... 28 図 4-13 証明書の格納順 ....................................................................................................................... 29 図 4-14 EXAMPLE4 コンストラクタ ..................................................................................................... 30 図 4-15 EXAMPLE4 SIGN()メソッド ...................................................................................................... 32 図 4-16 EXAMPLE4 VERIFY()メソッド................................................................................................... 33 図 4-17 EXAMPLE4 DOUPDATE()メソッド ............................................................................................ 34 図 4-18 KEYSTOREデータモデル図...................................................................................................... 36 図 4-19 EXAMPLE5 LOADKEYSTORE()メソッド .................................................................................... 39 図 4-20 EXAMPLE5 STOREKEYSTORE()メソッド .................................................................................. 40 図 4-21 EXAPMLE5 DOLISTENTRY()メソッド ....................................................................................... 42 図 4-22 EXAMPLE5 DOCOPYENTRY()メソッド...................................................................................... 44 図 4-23 EXAMPLE5 STOREPRIVATEKEY()メソッド................................................................................ 45 図 4-24 EXAMPLE5 LOADPRIVATEKEY()メソッド ................................................................................. 47 図 5-1 プロバイダの基本構造 .............................................................................................................. 48 図 5-2 MASTERCLASS.JAVAのクラス宣言............................................................................................. 49 図 5-3 MASTERCLASSのデフォルトコンストラクタ ............................................................................ 50 図 5-4 プロバイダの登録データの一部 ................................................................................................ 50 図 5-5 JDK 1.4の場合の JAVA.SECURITYの編集例 .............................................................................. 53 図 5-6 挙動観察用メソッド例 .............................................................................................................. 54 図 5-7 JARSIGNERの利用方法 ............................................................................................................... 54

Page 5: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

iii

― 表 目 次 ―

表 4-1 暗号アルゴリズムを指定する文字列表 ..................................................................................... 11 表 4-2 JAVAX.CRYPTO.CIPHERメソッド一覧......................................................................................... 12 表 4-3 一方向性ハッシュアルゴリズムを指定する文字列表 ............................................................... 18 表 4-4 JAVA.SECURITY.MESSAGEDIGESTのメソッド ............................................................................ 18 表 4-5 証明書検証機能とその機能提供クラス対応表 .......................................................................... 21 表 4-6 JAVA.SECURITY.CERT.PKIXBUILDERPARAMETERSが保有するデータ ....................................... 24 表 4-7 証明書検証用/証明書リポジトリ ............................................................................................... 28 表 4-8 SIGNATUREのメソッド .............................................................................................................. 29 表 4-9 署名アルゴリズムの書式 ........................................................................................................... 31 表 4-10 キーストアの機能とメソッド対応関係 ................................................................................... 37 表 5-1 プレフィックスと提供機能 ....................................................................................................... 51

Page 6: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

iv

(空白頁)

Page 7: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

1

1 はじめに

このパートでは、Java JCE (Java Cryptographic Extensions)に関する技術調査の内容を記述する。 この調査には、JDK(Java Development Kit)1.4([J2SE14])を利用した。JDKは、実行環境である JRE(Java Runtime Environment)と開発環境である SDK(Software Development Kit)とから構成される。

Javaに限らず暗号や署名などの機能は、ベースとなるアルゴリズム及びメカニズムの機能と特性とを考慮して、適切に利用されなけれならない。 特に、暗号や署名の機能をアプリケーションに組み込む際には、アルゴリズム及

びメカニズムに関するある程度の知識を有していることが前提となるが、これらの

前提知識は、機能の特性に関するものや、動作に必要とするデータなど多岐にわた

る。 本パートでは、これら前提となる知識に関しては詳述しない。必要に応じて、

「Part 1: 概要アーキテクチャ・機能・暗号技術とアルゴリズム」[SECAPI1]を参照されたい。

JDK 1.4がサポートしているセキュリティ関連機能には以下のものがある。 暗号 共通鍵、或いは、公開鍵を用いてデータを変換する機能。 暗号化はデータを一定のサイズを有するブロックに分割し、各ブロックを

単位として変換が行われる。 単純な暗号の利用法では、全てのブロックに対し同じ変換が施されるが、

これでは平文中に同じブロックが繰り返し現れる場合、変換後の暗号文でも

ブロックの繰り返しが再現されることになる。これでは暗号化した意義が下

がるので、繰り返しを外部からは判らないようにする必要がある。 この処理を動作モードと呼ぶ。動作モードには CBC、CFB、OFB等が定義されており、利用するモードによっては IV(イニシャルベクター)1が必要に

なる。 また、ブロックを単位として処理しているので、端数が発生した場合は不

足分を補う必要がある。これをパディングと呼ぶ。

1 IV: ブロックサイズと同じサイズを持ったランダムなデータ。通常、乱数を元に生成される。

Page 8: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

2

関連する規格としては FIPS 462、FIPS 813、PKCS #14、PKCS #5[PKCS]5

等、多数存在する。 Javaは、動作モード及びパディングを標準でサポートしており、さらに、アルゴリズムによっては、暗号の強度に関係する動作の段数や有効な鍵のサ

イズなどにも干渉できる([JCA])。 メッセージダイジェスト(一方向性ハッシュ) いわゆるメッセージダイジェストは、事実上任意長のデータから算出され

る固定の長さをもつ値である。メッセージダイジェストの長さはアルゴリズ

ム固有である。一般に、入力データはメッセージダイジェストより長いので、

2 つの異なる入力データに対して、同じメッセージダイジェストが計算される、いわゆる、「衝突」が発生する。 暗号のテクニックを利用し、衝突するふたつの入力データの発見を難しく

しているものを一方向性ハッシュと呼ぶ。一方向性ハッシュの代表的なもの

として MD5(Message-Digest 5、[RFC1321])や SHA-1(Secure Hash Algorithm 1、[RFC3174])等が存在する。

MAC(Message Authentication Code) 主に共有の秘密鍵を利用した、データ改ざんを検出するためのテクニック。

特に、一方向性ハッシュと組み合わせて使用されているアルゴリズムとして

は、HMAC(Hash-based MAC)がある。 Javaがサポートしている MACは HMACを基本とし、一方向性ハッシュアルゴリズムとしてMD5と SHA-1が利用できる。また、共有の秘密鍵の生成に PBE(Password Base Encryption)6を利用することもできる。 関連する規格は RFC 2104([RFC2104])等が存在する。

電子署名 公開鍵とプライベート鍵を利用した、データの改ざんを検出するためのテ

クニック。通常は、署名を施すデータからハッシュ値を計算し、プライベー

ト鍵で変換して署名値とする。

2 FIPS 46: FIPS(Federal Information Processing Standards) は NIST(National Institute of Standards and Technology)が発行する米国連邦政府調達規格。DES(Data Encryption Standard)を定義している規格。 3 FIPS 81: DESを単純に利用した場合の問題点の解決法を含む規格。現在では、DESだけで使用されているテクニックではなく、各種暗号アルゴリズムと組み合わせて利用されている。 4 PKCS #1: PKCS(Public-Key Cryptography Standards)は RSA Laboratoryが発行する、公開鍵暗号に関する規格のシリーズ。PKCS #1は RSAを利用した署名アルゴリズムや暗号アルゴリズムに関して定義している規格。 5 PKCS #5: パスワードを利用した暗号にまつわる規格。パスワードから共有秘密鍵を生成する方法からデータのフォーマットに関するところまで規程されている。 6 PBE: パスワードベースの暗号アルゴリズム。パスワードから共通鍵/IV(イニシャルベクター)を生成するメカニズムと暗号アルゴリズムを組み合わせたもの。

Page 9: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

3

関連する規格は FIPS 1867や PKCS #1等が存在する。また、これらの応用として PKCS #78を用いた署名も存在する。 Javaでは標準的に DSA(Digital Signature Algorithm)9と RSA10をサポ

ートしている。また、RSA署名の場合、利用するハッシュ関数が固定されていないので、MD5と SHA-1の利用が選択できる。

鍵系機能 共通鍵及び公開鍵の入出力や生成/管理を行う機能。基本的には、公開さ

れている規格を包含するよう出来ているが、一部独自の実装を持つものもあ

る。 これらの機能と関連する規格は PKCS #1、PKCS #8、PKCS #1211等が存在

する。 また、PKCSは ASN.1(Abstract Syntax Notation One)12が定める構文

規則と符号化規則に従う。 鍵入出力 鍵対生成 鍵交換 鍵生成 鍵束管理 秘密鍵入出力

安全な乱数 乱数とはランダムに生成される値の列であり、基本的にはどのような値が

出現するか予想できないものを指す。しかし、通常は擬似乱数生成アルゴリ

ズムが生成する擬似乱数が用いられる。擬似乱数は、周期性を有していたり、

分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

に偏りの度合いにより、擬似乱数生成アルゴリズムの優劣が決まる。 Java の擬似乱数生成機能は、一般的な利用に耐える程度のもの (java.util.Random) と 系 の 予 測 が 非 常 に 困 難 な 擬 似 乱 数 生 成 器(java.security.SecureRandom)を用意している。

7 FIPS186: DSA(DSS: Digital Signature Standard)を定義している規格。DSA自体は離散対数問題を根拠にした電子署名アルゴリズム。 8 PKCS#7: 暗号と署名に関するデータ形式等を規程している規格。 9 DSA: 離散対数問題を根拠にした署名アルゴリズム。 10 RSA: 因数分解の困難性を根拠にした暗号アルゴリズム。 11 PKCS#12: プライベート鍵や証明書・共有秘密鍵などを一括して扱うためのデータ形式に関する規格。この規格には要素の暗号化・データの完全性チェックなどが含まれており、X.509関連では標準的に使用される。 12 ASN.1: OSIの勧告である X.680に規程されているデータ・プロトコルを定義するための言語。ここにはエンコーディングに関することも記載されており、一種のデータ記述言語として利用することも出来る。 13 ハードウェアを利用して実装している本物の乱数生成機を持つものもある。

Page 10: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

4

アクセスコントロール 特定の動作を要求された場合、要求したエンティティ14がそれを行う権利を

有しているか確認し、必要に応じてブロックする行為を言う。 Java ではポリシーをキーワードにして各種動作の許可確認ができるようになっている。

証明書系機能 証明書入出力 公開鍵証明書をデータとして扱うための機能。Java では X.50915証明

書や PGP16証明書も一括して証明書として抽象化している。 証明書検証 証明書自身の妥当性を確認するためのメカニズム。

認証 通信相手の身元を確認するための機能。Javaでは Kerberos17、login、X.500等のメカニズムが用意されている。

免責機構(Exemption Mechanism) 暗号アルゴリズムの利用に関して、法律によって規制を受けている国も存

在する。また、暗号機能を含む製品は輸出の規制対象でもある。輸出規制は

一律的なものではなく、輸出相手国や輸出品の機能と性能の兼ね合いで規制

の程度が定められる。また、特定の機能を設けることにより、制限自体が緩

和される場合がある。この処置を免責機構と呼ぶ[JCA]。 処置の内容は各国の事情によるが、「鍵回復18」「鍵預託19」「鍵弱化20」のい

ずれかが一般的である。

14 エンティティ: 客観的な存在や物体。コンピュータ用語ではユーザやサービスプログラムを指す。 15 X.509: OSIの勧告、X500シリーズの一つ。X.509は公開鍵を用いた厳密な認証を行うために存在し、鍵のと認証対象の組み合わせを保証するために公開鍵証明書を用いる。 16 PGP(Prety Good Privacy): Philip R. Zimmermannを中心とした開発チームによって作られている暗号ソフトウェア。 17 Kerberos: MITが Project Athenaに利用するために作成された認証メカニズム。 18 何らかのメカニズムによって鍵を再現する方法。 19 信頼出来る第 3者機関に鍵を預ける方法 20 鍵預託または復元可能にする方法

Page 11: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

5

2 Javaのセキュリティ APIの構造

本節では Java JCEが含まれる「Javaにおけるセキュリティの構造」とその「実装における APIの仕様」に関して記述を行う。

Javaは、「Java言語仕様」と、バイトコードを実行する「仮想マシン仕様」から

構成される。 仮想マシンの仕様は、バグを含むプログラムから他のプログラムとその実行を保

護する、フェイルセーフを目指した仕様が多く含まれている。たとえば、バッファ

オーバランやメモリーリークからシステムを保護するようになっている。 しかし、意図的な不正行為から、プログラムとその実行を保護するためには、上

記の機構だけでは不十分であるので、これとは別にセキュリティを意識した機構が

組み込まれている。Javaのセキュリティ構造に関しての詳細は譲るが、主な機構はサンドボックスと呼ばれる実行環境とクラスローダーによる実行コードの読み取り

制限機能がそれに相当する。 JavaのセキュリティAPIを分類すると主に java.security.*/javax.crypto.*の 2系統に大別される[JCA]。 java.security.* 鍵管理、高度擬似乱数発生器、署名、鍵入出力、一方向性ハッシュ、証明書

パス検証、鍵対生成等が含まれており基本的な機能がまとめている。 javax.crypto.* 鍵交換、暗号、共通鍵入出力、共通鍵生成、MAC (Message Authentication Code)、免責機能など強力な機能をまとめている。

これらの機能をアプリケーション側から見た場合、公開鍵系の機能は

java.securityの配下に存在し、共通鍵系の機能は javax.cryptoの下にまとめられている21。これらの機能は個別のフレームワークへ分割して提供され、それぞれのフ

レームワークはプロバイダモデルで出来上がっている(図 2-1)。 また、全てのフレームワークに共通している構造は、フレームワークが定めたイ

ンターフェイスが持っている getInstance()メソッドを通じてプロバイダから実

装を取り出す点である。このメソッドは実装に付けられた名前をキーにして、プロ

21 一部 Cipherのような例外もある。

Page 12: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

6

バイダを検索する。 複数のプロバイダが存在する場合、検索の順序はシステムへ登録された順序に依

存する。また、検索するプロバイダを強制指定し実装を取り出すことも可能である

[JCA]。

Signature

MessageDigest

KeyPairGenerator

CipherKeyStore

KeyFactory

CertificateFactory

SecretKeyFactorySecureRandom

KeyGeneratorMac

KeyAgreement

ExemptionMechanismProvider

Provider

Provider

Provider

Security

Provider

Provider

Provider

Provider

Provider

Provider

Provider

Provider

Security

図 2-1 Security と参照するフレームワーク群

Page 13: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

7

3 Javaのセキュリティフレームワークにおける JCE

従来は、JCEはコア APIの外に置かれてが、JDK1.4からは JCEはコア APIに統合されている22。JCEが提供する機能は以下のようになっている[JCE]。 暗号化 鍵ジェネレータ 鍵ファクトリ SealedObject 鍵交換(Key Agreement) MAC 免責機構

現在の JCEはバージョンも 1.2.2となり、それ以前のものと比較してインターフェイスが改修された。 以下に、1.2.2以前からの変更点を上げる。 PBE(Password Based Encryption)の不足仕様の修正 新しい KeyStoreの追加 プロバイダ自身の完全性確認コードが要求されなくなった。 PKCS #1、#5、及び、#8のサポート

これらの変更により、旧来から存在する APIと連携しつつ、拡張された強力なセキュリティ機能を Javaアプリケーションにおいて利用できるようになった。

ワッセナー協約、及び、ワッセナー協約に準拠する国内法では、暗号技術と暗号

技術を利用した製品とは、戦略物資に分類され、輸出規制の対象となっている。JCEはこれらの協約及び法律に基づく輸出規制に対応するためのメカニズムも包含して

いる。JDKデフォルトの状態では、強力な暗号の利用が可能な状態になっているが、ポリシーによる制限、鍵預託などにより、各国の制限に対応できるようにもなって

いる。 JCEが、ワッセナー協約を遵守した暗号機能を提供するための具体的な方法は以下の 2通りの方法である[JCProv]。

1. JCEへプラグインするプロバイダ自体へ制限を課す方法

22 JDK 1.2/1.3ではオプショナルパッケージとして存在した。

Page 14: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

8

2. アプリケーションに免責機構を実装し政府の承認を取る方法 プロバイダを${JAVA_HOME}/jre/lib/ext 以外へインストールする場合やアプリ

ケーションへ制限を課す場合、ポリシーファイルが必要になる。ポリシーファイル

には暗号化以外の制限も記述できるが、以下では暗号関連に限定して扱う。 ポリシーファイルに記述できる制限は、基本的に使用アルゴリズムとアルゴリズ

ムに対する鍵長等である。ただし、免責機構が存在する場合、制限を緩めることが

できる可能性がある。免責機構の内容に関しては、各国の所轄省庁へ問い合わせる

必要がある。 実装を取り出せるプロバイダにするには、Sun microsystems 社が発行したコード署名用の DSA 証明書にて署名したアーカイブにて提供する必要がある。署名されていないアーカイブからは JCEの実装クラスが取り出せず、プロバイダとして動作することはできない23。

23 署名を必要としないフレームワークの場合は、問題なく動作する。

Page 15: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

9

4 Java JCEを利用したアプリケーション

本節では Java JCEを用いたサンプルコードを例示し解説を行う。解説を行うのは、以下の 5種類の機能である。

1. 暗号化と復号(Example1.Java) 2. 一方向性ハッシュ(Example2.Java) 3. 証明書検証(Example3.Java) 4. 電子署名の作成と検証(Example4.Java) 5. キーストアの操作(Example5.Java) サンプルコードは一括して本パートの末尾にも添付される。また、以下の解説中

でサンプルコードに付された行番号は、一括添付されたサンプルコード中の行番号

と一致する。

4.1 暗号化と復号

暗号化機能を提供するクラスは、javax.crypto.Cipherである。 javax.crypto.Cipherクラスは暗号アルゴリズムを抽象化しており、DES/RC2等の共通鍵暗号系(慣用暗号系)とRSA等の公開鍵系暗号の両者を提供可能なインターフェイスになっている。

Example1.javaは、暗号化と復号を行う実装例である。Example1のコンストラクタでは暗号化アルゴリズムの取得(図 4-1 / 65-66行)と動作に使用する鍵の生成(図 4-1 / 68-84行目)を行っている。

051: /**

052: * コンストラクタ

053: **/

054: protected Example1(

055: String algorithm,

056: byte[] key,

057: byte[] iv,

058: String inPath,

059: String outPath)

060: throws NoSuchAlgorithmException,

NoSuchPaddingException,

Page 16: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

10

InvalidKeySpecException, InvalidKeyException {

061: // 入出力情報を保存

062: this.inPath = inPath;

063: this.outPath = outPath;

064:

065: // 暗号アルゴリズムの実装を取得

066: this.cipher = Cipher.getInstance(algorithm);

067:

068: // 鍵の生成

069: String name = cipher.getAlgorithm();

070: int offset = name.indexOf('/');

071:

072: if(offset >= 0) {

073: name = name.substring(0, offset);

074: }

075: SecretKeyFactory factory =

SecretKeyFactory.getInstance(name);

076: KeySpec spec = null;

077: if(name.startsWith("DES")) {

078: spec = new DESKeySpec(key);

079: } else if(name.startsWith("TripleDES")

|| name.startsWith("DESede")) {

080: spec = new DESedeKeySpec(key);

081: } else {

082: spec = new SecretKeySpec(key, name);

083: }

084: this.secretKey = factory.generateSecret(spec);

085:

086: // イニシャルベクターをパラメータとして生成

087: algorithmSpec = new IvParameterSpec(iv);

088: }

図 4-1 Example1 コンストラクタ

Cipher クラスの実装を取得するために、実装と対応付けられている文字列をCipher.getInstance()メソッドへ渡す必要がある(図 4-1 / 66行)。文字列は、暗号アルゴリズム、暗号アルゴリズム/動作モード/パディングのどちらかでなけ

Page 17: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

11

ればならない。現在、定義されている暗号アルゴリズムを表 4-1にあげる。

表 4-1 暗号アルゴリズムを指定する文字列表

項目 指定 説明 AES Advanced Encryption Standard

であり NISTによって FIPS 197として規定されているブロック

暗号アルゴリズム。 Blowfish Bruce Schneier 氏の設計による

ブロック暗号アルゴリズム。 DES FIPS PUB 46-2で定義されてい

るブロック暗号アルゴリズム。 DESede DES を 3 重に使用するブロック

暗号アルゴリズム。 PBEWith<digest>And<encryption> パスワードベースの暗号化アル

ゴリズム。 PKCS#5で定義され、鍵とイニシャルベクターの生成に関する上

位規格。 RC2 RC4 RC5

RSA Data Security社が策定したブロック暗号アルゴリズム。鍵長

/段数を可変にできるのが特徴。

暗号アルゴリズム

RSA PKCS#1 で定義されている公開鍵暗号アルゴリズム。

NONE 指定なし。 CBC Cipher Block Chaining CFB Cipher Feed Back ECB Electric Code Book OFB Output Feed Back

動作モード

PCBC Propagating CBC NoPadding パディングなし。 OAEPWith<digest>And<mgf>Padding PKCS#1 v2 で定義されているパ

ディングスキーマ。 PKCS5Padding PKCS#5 で定義されているパデ

ィングスキーマ。

パディング

SSL3Padding SSL/TLS バージョン 3 で定義されているパディングスキーマ

表 4-1の全ての組み合わせが使用できるわけではないが、動作モード/パディン

グに関しては CBC/PKCS5Paddingは標準的に使用できるようである。 暗号アルゴリズムのみ指定した場合、実装依存のデフォルトが使用される。ただ

し、JDK 1.4 における Sun Microsystms 社提供の実装におけるデフォルトは、

Page 18: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

12

ECB/NONEもしくは NONE/NoPaddingが指定されているようである。 表 4-2に Javax.cryto.Cipherのメソッドの一覧をあげる。

表 4-2 Javax.crypto.Cipher メソッド一覧

メソッド 説明

void init(int mode, Key key) void init(int mode, Key key, SecureRandom random) void init(int mode, Key key, AlgorithmParameterSpec spec) void init(int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) void init(int mode, Key key, AlgorithmParameters spec) void init(int mode, Key key, AlgorithmParameters spec, SecureRandom random) void init(int mode, Certificate certificate) void init(int mode, Certificate certificate, SecureRandom random)

アルゴリズムを初期化するメソッド。

バリエーションは存在するが基本的に

は、動作に使用する鍵と動作モードを指

定することによって初期化するのが目的

である。

byte[] update(byte[] input) byte[] update(byte[] input, int offset, int length) int update(byte[] input, int offset, int length, byte[]) int update(byte[] input, int offset, int length, byte[], int dstOffset)

アルゴリズムへデータを入力し、変換

結果を受け取るメソッド。

byte[] wrap(byte[] key, int offset, int length) byte[] wrap(Key key)

鍵の暗号化(wrap)を行うメソッド。

Key unwrap(byte[] wrapped, String algorithm, int type)

暗号化(wrap)されている鍵を取り出すメソッド

byte[] doFinal() byte[] doFinal(byte[] input) byte[] doFinal(byte[] input, int offset, int length) int doFinal(byte[] buffer, int offset) int doFinal(byte[] input, int offset, int length, byte[] buffer)

最終処理を行うメソッド。アルゴリズ

ム中にフラッシュすべきデータなどがあ

る場合、そのデータが帰ってくる。 そのデータも update()の処理と同様に処理を行わなければならない。

Page 19: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

13

メソッド 説明

int doFinal(byte[] input, int offset, int length, byte[] buffer, int bufferOffset)

鍵インスタンスの生成には javax.crypto.SecretKeyFactoryを使用する(図 4-1 /

75行目)。 javax.crypto.SecretKeyFactoryは、java.security.spec.KeySpec型のインスタン

スから、javax.crypto.SecretKey型のインスタンスを生成する(図 4-2)。KeySpec型のインスタンスに関して、アルゴリズム固有のクラスを要求するものがあること

を注意しなければならない。

Cipher

SecretKeyFactory

SecretKey

KeySpec

Byte[]

Byte[]

図 4-2 java.security.spec.KeySpec 関連クラス/インスタンス関連図

暗号アルゴリズムとして DES/DESedeを使用する場合、SUNの実装を使用すると javax.crypto.spec.DESKeySpec ( 図 4-1 / 78 行 目 ) も し く は

javax.crypto.spec.DESedeKeySpec(図 4-1 / 80行目)が要求される。それ以外のアルゴリズムについては、javax.crypto.spec.SecretKeySpec(図 4-1 / 82行目)が使用できる場合が多い。 なお、このファクトリを使用するのは手動で任意の鍵を生成するためであり、ラ

ンダムな鍵を自動生成する場合は javax.crypto.KeyGeneratorを使用する。

Page 20: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

14

Cipherクラスのインスタンスは、初期化/データ入力/最終処理の 3ステップで使用する。初期化フェイズでは、動作方向(暗号化または復号)の指定、鍵、及び、

動作モード/パディングに必要なアルゴリズムパラメータを必要とする。 初 期 化 動 作 に 使 用 す る ア ル ゴ リ ズ ム パ ラ メ ー タ は 、

javax.crypto.spec.IvParameterSpecを使用する(図 4-1 / 87行目)。ただし、RC2または RC5 を使用する場合には、 javax.crypto.spec.RC2ParameterSpec/javax.crypto.spec.RC5ParameterSpec を使用する事もできるが、特別な場合を除いて必須ではない。 これらの処理に関してはコンストラクタの後半(図 4-1 / 68-87 行目)と

doEncryption()メソッド(図 4-3)/ doDecryption()メソッド(図 4-4)を参照のこと。doEncryption()メソッド(図 4-3)/ doDecryption()メソッド(図 4-4)は、処理方向(暗号化もしくは復号)を指定する行(図 4-3 / 96行目,図 4-4 / 108行目 赤字の部分のみが相違)を除けば、同じコードとなる。

093: protected void doEncryption()

094: throws InvalidKeyException, IOException,

IllegalBlockSizeException,

BadPaddingException, InvalidAlgorithmParameterException {

095: // 暗号化用に初期化

096: cipher.init(Cipher.ENCRYPT_MODE, secretKey, algorithmSpec);

097:

098: // 暗号化/復号に共通な処理

099: doProcess();

100: }

図 4-3 Example1 doEncryption()メソッド

Page 21: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

15

105: protected void doDecryption()

106: throws InvalidKeyException, IOException,

IllegalBlockSizeException,

BadPaddingException, InvalidAlgorithmParameterException {

107: // 復号用に初期化

108: cipher.init(Cipher.DECRYPT_MODE, secretKey, algorithmSpec);

109:

110: // 暗号化/復号に共通な処理

111: doProcess();

112: }

図 4-4 Example1 doDecryption()メソッド

データ入力に関しては、Example1.doProcess()メソッド(図 4-5)を参照し

ていただきたい。このメソッドではファイルからデータを読み取り、

Cipher.update()メソッドへ渡し、返ってきた分だけ(処理された分だけ)デー

タをファイルへ書き出している(図 4-5 / 133行目)。

114: /**

115: * アルゴリズムを駆動させてデータを変換するメソッド

116: **/

117: protected void doProcess() throws

IOException, IllegalBlockSizeException, BadPaddingException {

118: InputStream in = null;

119: OutputStream out = null;

120: byte[] buffer = new byte[8192];

121:

122: try {

123: // 入出力ファイルをオープン

124: in = new FileInputStream(inPath);

125: out = new FileOutputStream(outPath);

126:

127: while(true) {

128: // データの読み取りと変換を行う

129: int size = in.read(buffer);

130: if(size < 0) {

Page 22: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

16

131: break;

132: }

133: byte[] processed = cipher.update(buffer, 0, size);

134: if(processed != null && processed.length > 0) {

135: out.write(processed);

136: }

137: }

138: // 残りのデータを取り出して処理を終了

139: byte[] processed = cipher.doFinal();

140: if(processed != null && processed.length > 0) {

141: out.write(processed);

142: }

143: } finally {

144: // ファイルをクローズ

(略)

155: }

156: }

図 4-5 Example1 doProcess()メソッド

図 4-5の 120行目で、入力データの最大長を 8192バイトとしている。この 8192は 8 の倍数であるが、これは、通常の共通鍵暗号アルゴリズムのブロック長は 64ビット(8 バイト)であり、かつ、update()メソッドはブロック長の倍数でしか

受け付けない実装をとる可能性を考慮した結果である。 また、update()メソッドへ入力されるデータ(平文)の長さと、返されるデー

タ(暗号文)の長さが一致しない可能性があることに注意するべきである。たとえ

ば、暗号化の前に圧縮処理を行うなど、そもそも入力と出力のサイズが相異なる暗

号アルゴリズムを個別にプロバイダが提供するケースが考えられる。 終了可処理は Cipher.doFinal()メソッドを呼び出し、データの終了を宣言す

ることにより行う(図 4-5 / 139行目)。このメソッドから帰ってくるデータは暗号化処理の過程でバッファリングされたデータが処理されたものである。しかし、

Page 23: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

17

Cipher.doFinal()は、必ずしもデータを返すわけではない点に注意しなければ

ならない。Cipher.doFinal()メソッドでデータが返るか否かは、利用する暗号

アルゴリズム24に依存する。たとえば、パディングとして PKCS5Padding か

SSL3Paddingが指定された場合、Cipher.doFinal()メソッドは必ずデータを返

す。 実装例では、入力データのサイズが仮定できないので適量に分割して入力してい

るが、一度に全てのデータを渡すことができるなら、引数に入力となる平分を指定

できる Cipher.doFinal(byte[])等のメソッドを利用することも検討すべきで

ある。 また、Cipherのインスタンスはひとつのコンテキストのみ保有するので、スレッド間で同時にアクセスすることは勧められない。

4.2 一方向性ハッシュ

一方向性ハッシュを算出するためには、java.security.MessageDigestを使用する。このクラスはハッシュ値を計算するための機能が抽象化されており、基本的な使い

方は、データ入力、ハッシュ値取得の 2ステップを踏む。 Example2.javaは、JCEを用いてセキャアハッシュを計算する実装例である。 Example2のコンストラクタ(図 4-6)はMessageDigestのインスタンスを生成するために、MessageDigest.getInstance()メソッドを呼び出している(図 4-6 / 40行目)。

033: /**

034: * コンストラクタ

035: **/

036: public Example2(

037: String algorithm,

038: String inPath)

039: throws NoSuchAlgorithmException {

040: messageDigest = MessageDigest.getInstance(algorithm);

041: inPathName = inPath;

042: }

24 正確には、パディングの指定に依存する問題である。

Page 24: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

18

図 4-6 Example2 クラスのコンストラクタ

getInstance()メソッドは、要求するハッシュアルゴリズム名(メッセージダ

イジェストアルゴリズム名)を文字列として受け取り、登録されているプロバイダ

から実装を探し出す。 現在、定義されている文字列を表 4-3にあげる。

表 4-3 一方向性ハッシュアルゴリズムを指定する文字列表

指定 説明 MD2 RFC 1319で定義されているアルゴリズム。

128ビットの精度を持ったハッシュアルゴリズム。現在、積極的に使用する理由はあまりない。

MD5 RFC 1321で定義されているアルゴリズム。 128ビットの精度を持ったハッシュアルゴリズム。一般的に使用されているが、研究の結果攻撃方法が見つかっている。特に理由がない場合は使わ

ないほうが良い SHA-1 FIPS 180-1で定義されているアルゴリズム。

160 ビットの精度を持つハッシュアルゴリズム。一般的に使用されている。MD5 と比較し、こちらのほうが安全とされているのでデフォルトではこちらを使用することを薦める。

SHA-256 SHA-384 SHA-512

FIPS 180-2で定義されているアルゴリズム。 SHA-1 の後継として策定されたアルゴリズム。よりセキュアなハッシュを必要とする場合はこちらの使用を検討すると良い。

なお、文字列として定義されているものがすべて実装されているというわけでは

ない。 表 4-4に、java.security.MessageDigestが持つメソッドのリストをあげる。

表 4-4 Java.security.MessageDigest のメソッド

メソッド 説明 void reset() コンテキストをリセットし、初期状態へ戻すメソ

ッド void update(byte input)

void update(byte[] input)

void update(byte[] input, int offset, int length)

アルゴリズムへデータを入力するメソッド。

byte[] digest()

byte[] digest(byte[] input)入力したデータ全体に対するハッシュ値を取

得するメソッド。 同時に 現 テキ ト 使用終了を宣言する

Page 25: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

19

byte[] digest(byte[] input, int offset, int length)

データ入力に関して、実装例 Example2 の run()メソッド(図 4-7)を参考にし

て欲しい。

044: /**

045: * メインコード

046: **/

047: public void run() {

048: InputStream in = null;

049:

050: try {

051: in = new FileInputStream(inPathName);

052: byte[] buffer = new byte[1024];

053:

054: messageDigest.reset();

055: while(true) {

056: int size = in.read(buffer);

057: if(size < 0) {

058: break;

059: }

060: messageDigest.update(buffer, 0, size);

061: }

062: byte[] digest = messageDigest.digest();

063: printDigest(digest);

064: } catch(Exception e) {

065: e.printStackTrace();

066: System.exit(3);

067: } finally {

068: if(in != null) {

069: try {

070: in.close();

071: } catch(Exception e) {}

072: }

073: }

Page 26: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

20

074: }

図 4-7 Example2.run()メソッド

このケースではデータ量を仮定できないので、一回の入力量を 1024 バイトに制限し update()メソッドへの入力としている(図 4-7 / 52行目)。この 1024バイトに特別な意味はないので、適切な値へ変更してもかなわない。

データ入力が終了したならば、digest()メソッド(図 4-7 / 62行目)を呼び出し、ハッシュ値を獲得する。ハッシュ値は byte[]で返ってくるが、そのデータ量

は利用するハッシュアルゴリズムに依存するので、固定的な量を仮定してはならな

い。 また、ハッシュデータのサイズを得るには、getDigestLength()メソッドを利

用するか、配列の長さを調べる。 MessageDigestのインスタンスへデータを流し込むのに update()メソッド(図

4-7 / 60行目)を使用している点に注目してほしい。 この処理は、不定長データを考慮した結果であるが、一度に全てのデータを流し

込める場合には、ハッシュの対象となるデータを引数としてとることのできる

digest(byte[])メソッドを使用することもできる。 MessageDigest のインスタンスはひとつのコンテキストのみ保有するのでスレッド間で共有してはいけない。 しかし、スレッド間で再利用することに関して制限はない。ただし、その場合は

初めに reset()メソッド(図 4-7 / 54行目)を呼び出し、インスタンスの再初期化を行っておく必要がある。

4.3 証明書検証

証明書検証とは、与えられた証明書自体が信頼できるものであるかを確認する手

段である。この検証方法は一般的に規格に依存したものであるので、X.509、PGP、SPKI等、各々の規格に準拠した専用のアルゴリズムが必要になる。

しかし、全ての規格に対して一般的に考えられるアルゴリズムは、大別して下記

の 2種類存在する。 1. 証明書の連鎖を生成し妥当性検証を行うもの 2. あらかじめ保有するデータを利用して直接検証を行うもの Javaでは、この機能をパス生成機能とパス検証機能として用意し、用途に合わせ

Page 27: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

21

て使い分けられるようにしている(表 4-5)。

表 4-5 証明書検証機能とその機能提供クラス対応表

クラス名 説明

java.security.cert.CertPathValidator 与えられた証明書パスについて、妥当性

検証を行う。

java.security.cert.CertPathBuilder 検証したい証明書から正しい検証パスを

生成する。 通常、生成されたパスは「証明書パス検

証」プロセスを経由することにより妥当性

検証が行われている。 ただし、デフォルトで提供されている実装は X.509に関するもののみである。

提供されている実装の検証アルゴリズムは、RFC 3280で定義されているものになる。なお、検証アルゴリズムの詳細は、RFC 3280を参照して欲しい。

RFC 3280 で定義されているアルゴリズムを利用してパス生成/証明書検証行う場合、以下の 3つのデータを必要とする。 検証対象証明書 検証対象証明書は検証動作の対象となるデータである。

証明書リポジトリ 検証対象証明書や連鎖の途中に現れる証明書や CRL を発見するために使用される。リポジトリは複数指定する事が一般的である(メモリ中に存在する証明書リポジトリとネットワーク越しにアクセスするリポジトリなど)。

トラストアンカ トラストアンカとは、信頼の連鎖の基点である。全ての証明書パスはトラ

ストアンカへ繋がっている必要がある。トラストアンカ自体は単一である必

要は無く、必要な分だけ指定できるのが一般的である。 Example3.javaは、証明書の検証を行う実装例である。Example3のコンストラクタ前半は、コマンドラインオプションの解析を行っている(図 4-8 / 76-117行)。

067: /**

068: * 初期化メソッド

069: **/

070: public Example3(String argv[]) throws Exception {

071: Set internalRepository = null;

072:

073: internalRepository = new HashSet();

Page 28: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

22

074: trustAnchor = new HashSet();

075:

076: for(int i = 0 ; i < argv.length ; i++) {

077: String option = argv[i];

078:

079: if(option.equals("-t")) {

080: // トラストアンカをロードします

081: i++;

082: trustAnchor.add(

new TrustAnchor(loadCertificate(argv[i]), null));

083: } else if(option.equals("-i")) {

084: // 中間証明書をロードします

085: i++;

086: internalRepository.add(loadCertificate(argv[i]));

087: } else if(option.equals("-c")) {

088: // CRLをロードします

089: i++;

090: internalRepository.add(loadCRL(argv[i]));

091: } else if(option.equals("-")) {

092: // 不正なオプションが指定されました

093: printUsage();

094: System.exit(3);

095: } else {

096: // 検証対象をロードします

097: if(targetConstraint != null) {

098: throw new RuntimeException(

"Already specified");

099: }

100: X509Certificate target = loadCertificate(argv[i]);

101: X509CertSelector constraints

= new X509CertSelector();

102: // 対象証明書を設定。実は SUNの実装だとあまり意味は無い。

103: constraints.setCertificate(target);

104: // サブジェクトを設定。これは必須(SUNの実装の場合)

105: constraints.setSubject(

Page 29: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

23

target.getSubjectX500Principal().getEncoded());

106: // 証明書が複数あった場合を仮定して、特定の証明書を指定する。

107: constraints.setIssuer(

target.getIssuerX500Principal().getEncoded());

108: constraints.setSerialNumber(

target.getSerialNumber());

109:

110: // リポジトリから取得できるようにする。

111: internalRepository.add(target);

112:

113: targetConstraint = constraints;

114:

115: break;

116: }

117: }

118: // 検証アルゴリズムの取得

119: builder = CertPathBuilder.getInstance(SELECTED_BUILDER_NMAE);

120:

121: // 検証パラメータの作成

122: PKIXBuilderParameters pkixParams =

new PKIXBuilderParameters(trustAnchor, targetConstraint);

123:

124: // リポジトリを設定します

125: CertStoreParameters localStoreParameter =

126: new CollectionCertStoreParameters(

internalRepository);

127: CertStore localStore =

128: CertStore.getInstance(

129: SELECTED_CERT_STORE_NAME,

130: localStoreParameter);

131: pkixParams.addCertStore(localStore);

132:

133: pkixParams.setRevocationEnabled(false);

134: // テストプログラムでは CRLの検証を行わないようにします

135: params = pkixParams;

Page 30: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

24

136: }

図 4-8 Example3 コンストラクタ

後半は、実行環境の整備を行うためにパス生成アルゴリズムの取得(図 4-8 / 119行目)と検証パラメータの構築(図 4-8 / 122行目)を行っている。 パス生成アルゴリズムの獲得には、図 4-8の 119 行目に示したように

CertPathBuilder.getInstance()メソッドを使用する。デフォルトの状態で取

得できるアルゴリズムは PKIXのみとなる。 CertPathBuilderの使用法は、基本的には build()メソッドを呼び出すだけであ

る。それ以外の動作は実装内に閉じているので構築動作にユーザが関与する方法は

基 本 的 に 存 在 し な い 。 た だ し 、 Sun microsystems 社 の 実 装 で は

PKIXCertPathChecker を利用し、介入する方法もあるが、詳細は実装に関するドキュメント「Java Certification Path API プログラマーズガイド」を参照して欲しい。

build() メ ソ ッ ド を 呼 び 出 す た め に は 、

java.security.cert.CertPathBuilderParametersのインスタンスが必要になる。 このインスタンスとして使用できるクラスには PKIXBuilderParametersが存在する。 このクラスのアルゴリズムはRFC 3280の検証パラメータや検証動作に使用するリソースを収納するようになっている。表 4-6にインスタンスが保持するデータを上げる。

表 4-6 java.security.cert.PKIXBuilderParameters が保有するデータ

データ 目的

MaxPathLength パス構築やパス検証動作を行う場合の最大パス長を

指定するデータ。

CertStore パス構築時に使用する証明書リポジトリ。トラストア

ンカまでのパスを発見するために使用される。

Date 証明書の有効期間を確認する場合に使用される現在

時刻。

InitialPolicy RFC 3280で定義されている動作のうち、受け入れ可能なポリシーのセットを指定する。

TargetCertificateConstraints 検証対象証明書を特定するためのデータ。

TrustAnchor RFC 3280 のアルゴリズムで必要となるトラストアンカ。証明書のパスはトラストアンカに到達したこと

を持って、パスの構築ができたと見なす。

Page 31: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

25

データ 目的

ExplicitPolicy RFC 3280のアルゴリズムで要求されるフラグ。最終結果にポリシーの処理結果が必須であるか表明する。

InitialPolicyMapping RFC 3280のアルゴリズムで要求されるフラグ。ポリシーマッピングを使用するか表明する。

AnyPolicyInhibit RFC 3280のアルゴリズムで要求されるフラグ。ANYポリシーを有効にするかを表明する。。

RevocationEnable RevocationEnable 情報を確認するか表明するフラグ。

PKIXBuilderParameters のインスタンスの生成には、トラストアンカ情報と検

証対象証明書情報が必要となる。トラストアンカ情報の代わりに、KeyStore 型のインスタンスから自動生成することもできるが、実装例では個別の証明書ファイル

から生成している。 トラストアンカのインスタンスは、証明書のインスタンスと名前制約から生成で

きる。名前制約が存在しない場合は、代わりに nullを与えることで代用する。 外部から証明書を読み込み、Certificate のインスタンスを生成する機能は

java.security.cert.CertificateFactory が 提 供 す る 。 実 装 例 Example3 の

loadCertificate メソッド(図 4-9)と static 初期化子(図 4-10)を参照して欲しい。

138: /**

139: * 証明書を読み込むメソッド

140: **/

141: protected X509Certificate loadCertificate(String pathName)

142: throws IOException, CertificateException {

143: InputStream in = null;

144:

145: try {

146: in = new FileInputStream(pathName);

147: return

(X509Certificate)(factory.generateCertificate(in));

148: } finally {

149: if(in != null) {

150: try {

151: in.close();

152: } catch(Exception e) {}

Page 32: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

26

153: }

154: }

155: }

図 4-9 Example3 loadCertifictate

59: static {

60: try {

61: factory = CertificateFactory.getInstance("X.509");

62: } catch(Exception e) {

63: e.printStackTrace();

64: }

65: }

図 4-10 Example3 static 初期化子

CertificateFactory の イ ン ス タ ン ス は 、

CertificateFactory.getInstance()メソッド(図 4-10 / 61行目)へ対応する証明書のフォーマットを指定することにより獲得できる。PKIX で使用する場合は、X.509を指定する。

CertificateFactoryは、入力ストリームから java.security.cert.Certificate型もしくは java.security.cert.CRL型のインスタンスを生成する。

X.509 の フ ァ ク ト リ の 場 合 、 java.security.cert.X509Certificate / java.security.cert.X509CRL 型のインスタンスを返してくるので、最終的にはキャストして使用することになる(図 4-9 / 146-147行)。

検証対象証明書情報は、java.security.cert.X509CertSelector のインスタンスとして与える。このクラスは多数存在する証明書の中から、制約条件を満たす証明書

を選び出すのに使用される。 実装例 Example3のコンストラクタの前半を参照して欲しい。コマンドライン解析の最後のブロックが、X509CertSelectorのインスタンスを生成している部分である(図 4-8 / 97-108行)。 例では検証対象証明書を直接指定しているので、それだけで十分であるはずだが、

Sun microsystems 社の実装では、サブジェクトの指定が必須となる(図 4-8 / 104-105行)。これ以外にも、証明書を一意に決定するためにシリアル番号と署名者も特定しておく必要があると考えられる(図 4-8 / 106-108行)。

Page 33: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

27

PKIXBuilderParameters

TrustAnchorCertSelector

X509Certificate

CertStore(コレクション型)CertStore(LDAP型)

CertStoreCertStoreCertStore

X509CRL

CertificateFactoryInputStream

CertPathBuilder

CertPathBuilderResultCertPath

PKIXBuilderParameters

TrustAnchorCertSelector

PKIXBuilderParameters

TrustAnchorCertSelector

X509Certificate

CertStore(コレクション型)CertStore(LDAP型)

CertStoreCertStoreCertStore

CertStore(コレクション型)CertStore(LDAP型)

CertStoreCertStoreCertStoreCertStoreCertStoreCertStore

X509CRL

CertificateFactoryInputStreamInputStream

CertPathBuilder

CertPathBuilderResultCertPath

図 4-11 クラス/インスタンス関連図

ここまでのデータで、CertPathBuilder.build()を呼び出すデータはそろっ

たことになるが、PKIX の実装を動作させる情報のうち、証明書リポジトリに関する情報を特定できていない。 証明書リポジトリを指定するには java.security.cert.CertStore型のインスタンスを PKIXBuilderParameters.addCertStore()メソッド等を使用して指定する

(図 4-12)。

124: // リポジトリを設定します

125: CertStoreParameters localStoreParameter =

126: new CollectionCertStoreParameters(internalRepository);

127: CertStore localStore =

128: CertStore.getInstance(

129: SELECTED_CERT_STORE_NAME,

130: localStoreParameter);

131: pkixParams.addCertStore(localStore);

132:

133: pkixParams.setRevocationEnabled(false); // テストプログラムでは

134: // CRLの検証を行わないようにします

Page 34: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

28

135: params = pkixParams;

図 4-12 リポジトリィ設定のサンプルコード

CertStore のインスタンスは CertStore.getInstance()メソッドを通じて取

得する。デフォルトで用意されている証明書リポジトリは表 4-7の通りである。

表 4-7 証明書検証用/証明書リポジトリ

実装名 パラメータクラス 説明

LDAP java.security.cert.LDAPCertStoreParameters LDAPを使用したVM 外部に存在す

るリポジトリ

Collection java.security.cert.CollectionCertStoreParameters Collection を利用したVM内部に存在するリポジトリ

ただし、他クラスの場合とは異なり、getInstance()には、実装の名前だけで

はなく実装に対する固有のアルゴリズムパラメータも与えなければならない。 全ての要素がそろえば、PKIX のアルゴリズムを動作させうる状況になる。この時、対象となる証明書のパスが正しく生成でき、そのパスが妥当なものであるなら

ば、メソッド build()は java.security.cert.CertPathBuilderResult 型のインスタンスを返す。

PKIX ア ル ゴ リ ズ ム の 場 合 、 イ ン ス タ ン ス の 実 体 は

java.security.cert.PKIXCertPathBuilderResult となる。このクラスが保有する情報はCertPathBuilderResultが保有する java.security.cert.CertPathのインスタンスと RFC3280のアルゴリズムが出力する情報から構成されている。

CertPath のインスタンスは、getCertPath()メソッドを使って取得できる。

CertPath クラスは、生成されたパスそのものを表すクラスであり、パス自体をあらわすリストとパス自体を書き出すためのメソッド群から出来ている。 証明書の連鎖は、CertPath.getCertificates()メソッドから Listのインスタンスとして取得できる。 証明書の格納順に関して、APIリファレンスでは規定されていない。しかし、Sun

microsystems 社の実装の場合は、トラストアンカから検証対象方向へ向かって並んでいる(図 4-13)。また、出力されるリストにトラストアンカ証明書は含まれていない。

Page 35: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

29

検証対象証明書中間証明書中間証明書 検証対象証明書中間証明書中間証明書

図 4-13 証明書の格納順

ト ラ ス ト ア ン カ に 関 す る 情 報 は

PKIXCertPathBuilderResult.getTrustAnchor()メソッドから所得するこ

とができる。 このメソッドは当該パスが連結するトラストアンカを特定するために存在し、

PKIXBuilderParameters のコンストラクタへ与えたものの中から適切なものが返される。 ポリシーに関する処理結果は、getPolicyTree()メソッドから取得できる。本

メソッドの返すデータは、RFC 3280で定義されている valid_policy_treeに相当する。また、nullを返してきた場合も処理結果が nullになっている場合にマップされている。なお、ポリシーの木構造に関する詳細は RFC 3280を参照のこと。

JDK1.4 の javadoc にも記述されているが、本インターフェイスが要求している仕様として「スレッドセーフである必要は無い」とされている。また、この仕様は

インスタンスが内部的に使用する機能にも当てはまるので、CertStore のインスタンスなども共有することが無いように気をつけなければならない。

4.4 電子署名の作成と検証

Javaにおける電子署名とは、形式の指定がないバイト列データであり、PKCS #7や PKCS #1であることを仮定できない。 しかし、JDK 1.4 における Sun microsystems 社の実装に関して言うならば、

ASN.1の Signedマクロで signatureのビットストリングに使用できる形式をもっている。

電子署名機能を提供するクラスは java.security.Signatureである。このクラスの基本的な使用方法は初期化、データ入力、最終処理の 3ステップを行うことで動作する。

表 4-8 Signature のメソッド

メソッド名 説明

void initVerify(PublicKey) 署名検証動作を目的として初期化するメソ

Page 36: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

30

void initVerify(Certificate)

void initSign(PrivateKey) void initSign(PrivateKey, SecureRandom)

署名作成動作を目的として初期化するメソ

ッド。

void update(byte) void update(byte[]) void update(byte[], int, int)

署名作成/検証に必要なデータを入力する

メソッド。

boolean verify(byte[]) boolean verify(byte[], int, int)

既存の署名データを利用して、署名の検証

を行うメソッド。

byte[] sign() int sign(byte[], int, int)

入力されたデータから署名データを生成す

るメソッド。

Example4.javaは、電子署名の作成と検証を行う実装例である。 実装例クラス Example4のコンストラクタでは、署名操作に使用する鍵の読み込みと署名アルゴリズム自体の取得を行っている(図 4-14 / 57-59行)。

44: /**

45: * コンストラクタ

46: **/

47: public Example4(

48: String keyStoreFileName,

49: String keyStoreType,

50: String entryName,

51: String password,

52: String hashAlgorith)

53: throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {

54: // 使用する鍵を特定

55: loadKey(keyStoreType, keyStoreFileName, entryName, password.toCharArray());

56:

57: // 署名アルゴリズムを特定

58: String keyAlgorithm = publicKey.getAlgorithm();

59: signatureAlgorithm = Signature.getInstance(hashAlgorith + "with" + keyAlgorithm);

60: }

図 4-14 Example4 コンストラクタ

Page 37: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

31

アルゴリズムの取得は、Signature.getInstance()メソッドを通じて行われ

る。アルゴリズムの取得にはアルゴリズム名をパラメータとして要求する。以下に

アルゴリズム名のパターンを示す。

表 4-9 署名アルゴリズムの書式

文字列 説明

<HashAlgorithm>with<KeyAlgorithm>

鍵アルゴリズム名と使用されるハッシュ関数名で表される

署名アルゴリズム。RSA署名の場合、鍵アルゴリズムだけではハッシュアルゴリズム特定できないのでこの形式を使

用する。署名アルゴリズムを指定する形式としては最も一

般的な形式となる。

鍵アルゴリズム名 鍵アルゴリズムだけで署名アルゴリズム全体が記述できる

場合に使用できる形式。主に鍵アルゴリズム自体からハッ

シュアルゴリズムなどが特定できる場合に使用される

(DSA等)。 JDKがデフォルトで、保有しているアルゴリズムは以下の 4種類である。 MD2withRSA

MD5withRSA

SHA1withRSA

DSA 初期化動作に関しては、実装例クラス Example4の sign()メソッド(図 4-15)及び verify()メソッド(図 4-16)を参照して欲しい。 コンテキストに応じて initSign()メソッド(図 4-15 / 111行目) と initVerify()メソッド(図 4-16 / 165行目)を呼び分け、動作に使用する鍵を特定し、コンテキストの初期化を行っている。

096: /**

097: * ターゲットへの署名データを作成するメソッド

098: **/

099: protected void sign(

100: String targetFileName,

101: String signatureFileName)

102: throws IOException, SignatureException, InvalidKeyException {

103: if(privateKey == null) {

104: throw new RuntimeException("Private key dose not exist");

105: }

106: // 秘密鍵で署名アルゴリズムを初期化

Page 38: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

32

107: signatureAlgorithm.initSign(privateKey);

108: // 署名対象データをアルゴリズムへ入れる

109: doUpdate(targetFileName);

110: // 署名を獲得

111: byte[] signature = signatureAlgorithm.sign();

112:

(略)

126: }

図 4-15 Example4 sign()メソッド

Page 39: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

33

131: /**

132: * ターゲットへの署名データを検証するメソッド

133: **/

134: protected void verify(

135: String targetFileName,

136: String signatureFileName)

(略)

164: // 公開鍵で署名アルゴリズムを初期化

165: signatureAlgorithm.initVerify(publicKey);

166: // 署名対象データをアルゴリズムへ入力

167: doUpdate(targetFileName);

168: // 署名の確認

169: if(signatureAlgorithm.verify(signature)) {

170: System.out.println("Signature is valid");

171: } else {

172: System.out.println("Signature is invalid");

173: }

174: }

図 4-16 Example4 verify()メソッド

Page 40: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

34

データ入力動作に関しては、doUpdate()メソッド(図 4-17)を参照して欲しい。 このメソッドの使用法は、MessageDigestやCipher等で用意されているものと、基本的に同じである。 ただし、MessageDigest クラス/Cipher クラスのメソッドと違い、使用しないケースは存在せず、データ入力には必ず doUpdate()メソッドを使用する。内部処理

では、signatureAlgorithm.update()を用いている(図 4-17 / 190行目)。

176: /**

177: * 署名対象データを署名アルゴリズムへ入力

178: **/

179: protected void doUpdate(String targetFileName)

throws IOException, SignatureException {

180: InputStream in = null;

181: try {

182: in = new FileInputStream(targetFileName);

183: byte[] buffer = new byte[1024];

184:

185: while(true) {

186: int size = in.read(buffer);

187: if(size < 0) {

188: break;

189: }

190: signatureAlgorithm.update(buffer, 0, size);

191: }

192: } finally {

193: if(in != null) {

194: try {

195: in.close();

196: } catch(Exception e) {}

197: }

198: }

199: }

図 4-17 Example4 doUpdate()メソッド

最終処理動作は、それぞれ、 Signature.sign()メソッド、或いは、

Page 41: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

35

Signature.verify()メソッドを呼び出すことで行われる。これらのメソッドは、

初期化時に initSign()メソッドと initVerify()メソッドのどちらのメソッドを使用したかで、使い分けなければならない。 このコンテキスト管理は Signatureが行っており、ステートが合わない場合は例外(SignatureException)が発生する。 署名作成を行う場合、sign()メソッド(図 4-15 / 111行目)を使用する。この

メソッドは、署名を作成するためにある。 署名は byte[]で返され、サイズの仮定をすることはできない。ただし、通常は

署名アルゴリズムに RSA系を利用した場合、鍵のサイズに等しく、DSA系を使用した場合は利用されるハッシュアルゴリズムの出力の 2倍程度になる25。 署名検証を行う場合、verify()メソッド(図 4-16 / 169行目)を使用する。 このメソッドは与えられた署名データと現在のコンテキストを比較するために存

在する。比較結果は booleanで返される。署名データとして不正なものを与えられた場合、不正の原因に応じた例外を発生する。

4.5 キーストアの操作

Java の 証 明 書 リ ポ ジ ト リ の 一 種 と し て 、 キ ー ス ト ア が あ り 、

java.security.KeyStore がその実体である。このクラスの目的は、主に秘密鍵と公開鍵証明書の対を管理するために存在している。 このクラスが扱う鍵は java.security.Keyであるため、公開鍵のために存在するインターフェイスではない。しかし、実際には実装に依存する。 このクラスのインスタンスは getInstance()メソッドを利用して、実装の名前から実装を引き出す。参考までに Sun microsystemsの実装を例にあげると以下の 2種類の実装がある。 JKS

Sun microsystems社のプロバイダが提供する Java独自のキーストアタイプ。Javaでは事実上の標準。この実装を使用するとストアからの読み込みと書き出しができる。getDefaultType()が返す文字列も、通常は JKSである。

PKCS12 PKCS #12 で定義されている個人情報転送用のフォーマット。X.509 関連では標準的に使用される。しかし、Sun microsystems社の実装では書き出しが出来ず、また JDKのバージョンによっては動作すらしない。

25 厳密には離散対数の底の位数の 2倍である。

Page 42: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

36

KeyStoreが仮定しているデータモデルは図 4-18のようになっている。

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

エイリアス名

証明書

秘密鍵

エイリアス名

証明書

秘密鍵

エイリアス名

証明書

秘密鍵

KeyStore

図 4-18 KeyStore データモデル図

KeyStoreの基本的なデータ単位としてエントリーが定義されている。 エントリーは、生成日時とエイリアス名を持っており、エイリアスをキーにして

管理されている。エイリアスはヒューマンリーダブルな文字列であり、エントリー

の名前として使用する。 エントリーには 2つの種類、証明書エントリーと鍵エントリーが存在する。 証明書エントリー 単一の証明書が収納されている。トラストアンカや中間 CA の証明書などを格納するために使用する。

鍵エントリー 秘密鍵と複数/単一の証明書が収納されている。秘密鍵は「パスワード」ベースの暗号化処理が施されている。

キーストア全体では、パスワードベースの完全性処理や暗号化処理が施されてい

るが、全ての実装がそうであるわけでもなく、オプショナルな仕様になっている。

Page 43: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

37

表 4-10にキーストアの機能と KeyStore クラスが保持しているメソッドの対応

関係をあげる。

表 4-10 キーストアの機能とメソッド対応関係

メソッド 機能説明

Key getKey(String, char[]) 与えられたエイリアスとパスワードを使

用して鍵を取り出すメソッド。

Certificate getCertificate(String)

与えられたエイリアスを使用して証明書

を取り出すメソッド。取り出し対象となる

証明書は単一のものとなる。

Certificate[] getCertificateChain(String)

与えられたエイリアスを使用して証明書

を取り出すメソッド。取り出し対象となる

証明書はパスを形成していると考えられ

る一連の証明書。

Date getCreationDate(String) エントリーが作成された日時を返すメソ

ッド。

void setKeyEntry(String, Key, char[], Certificate[])

鍵に関するエントリーを追加するメソッ

ド。 void setCertificateEntry(String, Certificate)

証明書に関するエントリーを追加するメ

ソッド。

void deleteEntry(String) 与えられたエイリアス名を持つエントリ

ーをキーストアから削除するメソッド

Enumeration aliases() キーストア上に存在するエントリーのエ

イリアス名一覧を返すメソッド

Boolean containsAlias(String) 指定されたエイリアスがキーストアに存

在するか確認するメソッド

Boolean isKeyEntry(String) 指定されたエントリーがキーエントリー

であるか確認するメソッド。

Boolean isCertificateEntry(String)

指定されたエントリーが証明書エントリ

ーであるか確認するメソッド。

void load(InputStream, char[])キーストアをストリームから読み込むメ

ソッド

void store(OutputStream, char[])キーストアをストリームへ書き出すメソ

ッド。

キーストアの基本的な機能は以下の 3つに分類することができる。 1. エントリー調査系メソッド

aliases() メ ソ ッ ド 、 isKeyEntry() メ ソ ッ ド 、 及 び 、

isCertificateEntry()メソッドが該当する。これらのメソッドは、キー

Page 44: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

38

ストア中に存在するエントリーに関する調査を行うことを目的としており、

一覧の作成や当該エントリーの種類判別などを行う。 2. エントリー操作系メソッド

setKeyEntry()メソッド、setCertificateEntry()メソッド、及び、

deleteEntry()メソッドが該当する。これらのメソッドは、現在のストア

に対する追加と削除とを目的としている。 特に、注意しなければならない点として、存在するエントリーの上書きはで

きない点を上げられる。上書きが必要な場合、既存のエントリーを削除し、

その後にエントリーの追加を行わなければならない。 3. キーストア入出力メソッド

load()メソッド、store()メソッドが該当する。これらのメソッドは入出

力ストリームとオペレーションに必要なパスワードを必要とする。ただし、

パスワードが必要なオペレーションであることが確認できている場合、nullで代用するころができる。

本クラスを使う場合の基本的な流れは以下の 3ステップを踏む。 1. キーストアの読み込み 2. オペレーション 3. キーストアの書き出し Example5.Javaは、JCEを用いキーストアの操作を行う実装例である。 ステップ 1及び 3に関しては、実装例クラス Example5の loadKeyStore()メ

ソッド(図 4-19) /と storeKeyStore()メソッド(図 4-20)とを参照し、各オペレーションに関しては doCopyEntity()メソッド(図 4-22)、doDeleteEntity()メソッド、及び、 doListEntity()メソッド(図 4-21)を参照して欲しい。 まず、loadKeyStore()メソッド(図 4-19)では、キーストアのロード及び新規作成を行っている。

378: /**

379: * キーストアを読み取るメソッド

380: **/

381: protected KeyStore loadKeyStore(String path, char[] passwd)

382: throws KeyStoreException {

383: InputStream in = null;

384: KeyStore instance = null;

385: try {

386: in = new FileInputStream(path);

Page 45: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

39

387: } catch(IOException e) {

388: in = null;

389: }

390: try {

391: instance = KeyStore.getInstance(KeyStore.getDefaultType());

392:

393: instance.load(in, passwd);

394: } catch(IOException ioe) {

395: } catch(CertificateException ce) {

396: ce.printStackTrace();

397: } catch(NoSuchAlgorithmException nsae) {

398: nsae.printStackTrace();

399: } finally {

400: if(in != null) {

401: try {

402: in.close();

403: } catch(Exception e) {}

404: }

405: }

406: return instance;

407: }

図 4-19 Example5 loadKeyStore()メソッド

KeyStore のインスタンスを取得するためには getInstance()メソッドへ実装

の名前を渡す事で取得できる(図 4-19 / 391行目)。指定できる実装名は、前述したとおりである。 getInstance()メソッドは、未初期化のキーストアを作成する。初期化するため

には load()メソッド(図 4-19 / 393行目)を呼び出し、ストアの読み込みと初期化を行わなければならない。 load()メソッドの動作には、入力ストリームとキーストアに対するパスワードを

要求する。実装がパスワードを必要とし、そのパスワードが一致していなかった場

合、ストアの読み込みに失敗する。 新規に作成されるストアに関して、注意しなければならない。新規にストアが作

成される場合、本来であれば入力ストリームからストアを読み込むことはできない。

しかし、ストアのインスタンスを初期化するためには load()メソッドを呼び出す

必要がある。 そこで、新規ストアの初期化の場合、入力ストリームとして nullを与える。新規

Page 46: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

40

作成時にはパスワードに意味は無いので nullを指定しても構わない。 次に、キーストアの書き出しに関して、storeKeyStore()メソッド(図 4-20)を参照して欲しい。

358: /**

359: * キーストアを書き出すメソッド

360: **/

361: protected void storeKeyStore(KeyStore instance,

String path, char[] passwd) {

362: OutputStream out = null;

363:

364: try {

365: out = new FileOutputStream(path);

366: instance.store(out, passwd);

367: } catch(Exception e) {

368: e.printStackTrace();

369: } finally {

370: if(out != null) {

371: try {

372: out.close();

373: } catch(Exception e) {}

374: }

375: }

376: }

図 4-20 Example5 storeKeyStore()メソッド

使用するメソッドは store()メソッド(図 4-20 / 366行目)である。本メソッドは出力ストリームと、書き出しに使用するパスワードを要求する。 ただし、load()メソッド(図 4-19 / 393行目)と同様に、実装が要求しない場合は与える必要は無い。

Page 47: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

41

Example5.doListEntry()メソッド(図 4-21)を参照して欲しい。

202: /**

203: * エントリーの一覧表示を行うメソッド

204: **/

205: public void doListEntity() {

206: System.out.println(srcKeyStore + " has flowing entries.");

207: try {

208: KeyStore instance =

loadKeyStore(srcKeyStore, srcKeyStorePass);

209: Enumeration aliases = instance.aliases();

210:

211: while(aliases.hasMoreElements()) {

212: String name = (String)(aliases.nextElement());

213: System.out.println(name + ":");

214: Certificate certificate = null;

215: Date creationDate = null;

216:

217: try {

218: certificate = instance.getCertificate(name);

219: } catch(Exception e) {

220: certificate = null;

221: }

222: try {

223: creationDate =

instance.getCreationDate(name);

224: } catch(Exception e) {

225: creationDate = null;

226: }

227: if(creationDate != null) {

228: System.out.println(

"¥tit was created at " + creationDate + ".");

229: }

230: if(certificate != null) {

231: System.out.println("¥thave certificate.");

Page 48: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

42

232: if(certificate instanceof X509Certificate) {

233: X509Certificate x509 = (X509Certificate)certificate;

234: System.out.println( "¥t¥tSubject: " + x509.getSubjectX500Principal());

235: System.out.println(

"¥t¥tIssuer: " + x509.getIssuerX500Principal());

236: System.out.println( "¥t¥tSerial: " + x509.getSerialNumber().toString(16));

237: }

238: }

239: if(instance.isKeyEntry(name)) {

240: System.out.println("¥thave private key.");

241: }

242: }

243: } catch(Exception e) {

244: }

245: System.out.println("done.");

246: }

図 4-21 Exapmle5 doListEntry()メソッド

doListEntry()メソッドは、キーストア中のエントリーの一覧を作成するメソ

ッドである。キーストアからエントリー全体を取得するために aliases()メソッ

ド(図 4-21 / 209行目)を使っている。このメソッドは Java.util.Enumerationインターフェイスを使って列挙としてデータを返す。 この列挙型データにはエントリーのエイリアスのみ含まれており、エントリーの

型までは不明である。エントリーの型を特定するためには isKeyEntry()メソッド

(図 4-21 / 239行目)または isCertificateEntry()メソッドを使用して型の確認を行う。

Page 49: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

43

エントリーから鍵ないし証明書を取得するには getKey()メソッド(図 4-22 /

163 行目)、getCertificate()メソッド(図 4-21 / 218 行目)、及び、 getCertificateChain()メソッド(図 4-22 / 168行目)を使用する。 逆に、エントリーをキーストアに追加するためには、エントリーの型に応じて

setKeyEntry()メソッド(図 4-22 / 175行目)、及び、setCertificateEntry()メソッド(図 4-22 / 173行目)を使用する。 上記 5つのメソッドは、エイリアスをキーにしてエントリーへアクセスする。鍵関連のメソッドについてはパスワードも使用する。理由は前述した通りである。 これらの使用例は Example5.doCopyEntry()メソッド(図 4-22)を参照して欲しい。このメソッドは元になるキーストアから別のキーストアへエントリーのコ

ピーを行う動作を行っている。注目して欲しい部分は get 系のメソッドと set 系メソッドの仕様の違いである。

get 系メソッドでは、項目ごとに独立のメソッドを介してエントリーから項目データを取り出す仕様になっている(getCertificate()、getCreationDate()

など)。 これに対し、set 系メソッドでは、ひとつのメソッドでエントリーに関する全て

の項目データを一括して設定する仕様になっている。これは、キーストアのポリシ

ーとしてエントリーの上書きが許可されないため、エントリーを作成した後項目デ

ータを追記することができないことに理由がある。

151: /**

152: * エントリーのコピーを行うメソッド

153: **/

154: public void doCopyEntity() {

155: try {

156: KeyStore source =

loadKeyStore(srcKeyStore, srcKeyStorePass);

157: KeyStore dest =

loadKeyStore(dstKeyStore, dstKeyStorePass);

158:

159: Key key = null;

160: Certificate[] certificates = null;

161:

162: try {

163: key = source.getKey(alias, keyPass);

164: } catch(Exception e) {

Page 50: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

44

165: key = null;

166: }

167: try {

168: certificates = source.getCertificateChain(alias);

169: } catch(Exception e) {

170: certificates = null;

171: }

172: if(key == null) {

173: dest.setCertificateEntry(alias, certificates[0]);

174: } else {

175: dest.setKeyEntry(alias,key, keyPass, certificates);

176: }

177: storeKeyStore(dest, dstKeyStore, dstKeyStorePass);

178: } catch(Exception e) {

179: e.printStackTrace();

180: }

181: }

図 4-22 Example5 doCopyEntry()メソッド

以上が、キーストア自身に可能なオペレーションである。ここまでで、Javaのみで構成されたアプリケーションを作成するなら十分な機能といえるが、他のアプリ

ケーションとの連携やデータのインポートとなると、鍵や証明書のインポートとエ

クスポートの機能が不足している。 これらの機能はキーストアとは別のフレームワークを利用して実装されている。 証明書の読み込みに関しては4.3 で説明しているので省略するが、証明書の書き出しに関しては Certificate.getEncoded ()メソッド(図 4-23 / 260行目)を用いて行う。 このメソッドは証明書のタイプに合わせてエンコード形式が一意に決定されてお

り、X509Certificateの場合は、DERエンコードと定義されている。 あとは、このバイト列を適当なストリームへ書き出す事により、証明書の書き出

しか出来たことになる。

Page 51: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

45

秘密鍵の入出力には Example5の storePrivateKey()メソッド(図 4-23)及び loadPrivateKey()メソッド(図 4-24)を参照して欲しい。

65: static protected final String[] knownKeyType = {”DSA”, ”RSA”}

248: /**

249: * 秘密鍵スペックを書き出すメソッド

250: **/

251: protected void storePrivateKey(Key key) throws IOException {

252: OutputStream out = null;

253:

254: try {

255: KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm());

256: KeySpec spec = factory.getKeySpec(key, PKCS8EncodedKeySpec.class);

257:

258: System.out.println( "Store private key into " + privateKeyFile);

259: out = new FileOutputStream(privateKeyFile);

260: out.write(((PKCS8EncodedKeySpec)(spec)).getEncoded());

261: System.out.println("done.");

262: } catch(Exception e) {

263: throw new IOException(e.getMessage());

264: } finally {

265: if(out != null) {

266: try {

267: out.close();

268: } catch(Exception e) {}

269: }

270: }

271: }

図 4-23 Example5 storePrivateKey()メソッド

65: static protected final String[] knownKeyType = {“DSA”, “RSA”};

Page 52: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

46

273: /**

274: * 秘密鍵を読み込むメソッド

275: **/

276: protected Key loadPrivateKey() throws IOException {

277: InputStream in = null;

278:

279: try {

280: File file = new File(privateKeyFile);

281: byte[] encoded = null;

282:

283: if(file.exists() && file.isFile() && file.canRead()) {

284: in = new FileInputStream(file);

285: encoded = new byte[(int)(file.length())];

286: int offset = 0;

287: while(offset < encoded.length) {

288: int size = in.read( encoded, offset, encoded.length - offset);

289: if(size < 0) {

290: throw new IOException("Unexpected EOF");

291: }

292: offset += size;

293: }

294: PKCS8EncodedKeySpec spec =

new PKCS8EncodedKeySpec(encoded);

295: for(int i = 0 ; i < knownKeyType.length ; i++) {

296: try {

297: KeyFactory factory =

KeyFactory.getInstance(

knownKeyType[i]);

298: return factory.generatePrivate(spec);

299: } catch(Exception e) {}

300: }

301: throw new IOException("Unknown key type");

302: } else {

303: throw new IOException(

Page 53: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

47

"Invalid path ¥"" + privateKeyFile + "¥"");

304: }

305: } finally {

306: if(in != null) {

307: try {

308: in.close();

309: } catch(Exception e) {}

310: }

311: }

312: }

図 4-24 Example5 loadPrivateKey()メソッド

これらのメソッドで重要な役目を果たすのが Java.security.KeyFactory である。このクラスは鍵と KeySpecを相互に変換するために存在する。 インスタンスの取得は getInstance()メソッド(図 4-23 / 255行目)へアルゴリズム名を渡すことにより行う。デフォルトの状態において、アルゴリズム名は鍵ア

ルゴリズムと同じものが必要になり、ファクトリの生成時点で鍵のアルゴリズムが

判明していなければならない。 KeyをKeySpecに変換するためにKeyFactoryのインスタンスを生成する際には、

getAlgorithm()メソッドにより鍵アルゴリズムを取得できるため、この制約は問

題にならない(図 4-23 / 255 行目)。逆に、KeySpec を Key に変換する際には、KeySpec のインスタンスから鍵アルゴリズムを取得する手段が提供されていないため、必要な KeyFactory のインスタンスを直接生成することはできない。loadPrivateKey()メソッド(図 4-24)の例に示したように、鍵アルゴリズム毎に順番に KeyFactoryのインスタンスを生成してみて、うまく Keyに変換できるか試してみる必要がある(図 4-24 / 295~300行目)。 loadPrivateKey()メソッドの例では、プライベート鍵に変換しているので、

生成する KeySpecは PKCS8EncodedKeySpec(図 4-24 / 294行目)を指定している。公開鍵を対象とする場合は、X509EncodedKeySpecを指定すればよい。

Page 54: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

48

5 Java JCEのプロバイダの実装

本節ではプロバイダの実装例を解説する。 プロバイダは、図 5-1の様にマスタークラスと実装から構成される。

マスタークラス

Signature.MD2withRSA=org.jnsa.ChallengePKI2003.signature.MD2withRSA

Signature.MD4withRSA=org.jnsa.ChallengePKI2003.signature.MD4withRSA

Signature.MD5withRSA=org.jnsa.ChallengePKI2003.signature.MD5withRSA

Signature.SHA1withRSA=org.jnsa.ChallengePKI2003.signature.SHA1withRSA

Cipher.RSA= org.jnsa.ChallengePKI2003.cipher.RSA

SPI実装クラス

SPI実装クラス

SPI実装クラス

プロバイダ

マスタークラス

Signature.MD2withRSA=org.jnsa.ChallengePKI2003.signature.MD2withRSA

Signature.MD4withRSA=org.jnsa.ChallengePKI2003.signature.MD4withRSA

Signature.MD5withRSA=org.jnsa.ChallengePKI2003.signature.MD5withRSA

Signature.SHA1withRSA=org.jnsa.ChallengePKI2003.signature.SHA1withRSA

Cipher.RSA= org.jnsa.ChallengePKI2003.cipher.RSA

SPI実装クラス

SPI実装クラス

SPI実装クラス

プロバイダ

図 5-1 プロバイダの基本構造

マスタークラスとは、提供可能なアルゴリズム名と実装を結合させるためのプロ

パティを保持するクラスであり、実装は各フレームワークの SPI(Service Provider Interface)を継承したクラスである。

マスタークラスは Java.security.Security へ登録され、各フレームワークはそれらを参照する。

Example6 ディレクトリにある MasterClass.java、CaesarCipher.java、及び、

CaesarCipherKey.java は、シーザー暗号を Java JCE プロバイダとして実装した例である。

Page 55: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

49

まず、実装例 6のExample6/MasterClass.Javaのクラス宣言を参照して欲しい。

018: /**

019: * サンプルプロバイダのマスタークラス

020: **/

021: public class MasterClass extends Provider {

022: static protected final String PROVIDER_NAME = "JNSA";

023: static protected final double PROVIDER_VERSION = 1.0;

024: static protected final String PROVIDER_INFO =

"This provider is sample implementation for ChallengePKI 2003";

図 5-2 MasterClass.Java のクラス宣言

マスタークラス自体は java.security.Providerを継承しており(図 5-2 / 21行目)、以下のデータを保持する。 実装者の名前(図 5-2 / 22行目) 実装のバージョン(図 5-2 / 23行目) 実装に関するコメント(図 5-2 / 24行目) これらの情報はフレームワークの表面に現れることはまれであるが、特定の実装

などを必要とする場合は、指定される場合もある。また、Provider 自体はjava.util.Properties を継承しており、アルゴリズム名と実装クラスの結合にはPropertiesと同様なデータフォーマットと入出力メソッドが利用できる。

MasterClassのデフォルトコンストラクタ(図 5-3)を参照して欲しい。

026: /**

027: * コンストラクタ

028: **/

029: public MasterClass() {

030: super(PROVIDER_NAME,

PROVIDER_VERSION,

PROVIDER_INFO);

031:

032: AccessController.doPrivileged(new

Java.security.PrivilegedAction()

{

033: public Object run() {

034: put("Cipher.Caesar",

Page 56: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

50

"org.jnsa.ChallengePKI2003.Example6.CaesarCipher");

035:

036: return null;

037: }

038: }

039:

040: }

図 5-3 MasterClass のデフォルトコンストラクタ

マスタークラスは通常、デフォルトコンストラクタを実装しなければならない。

しかし、Providerのコンストラクタは以下の 3つの引数を必要とする(図 5-3 / 30行目)。 名前 バージョン番号 実装に関する情報 これらの内容は実装者に任されており、適切に与えなければならない。マスター

クラスではデフォルトコンストラクタを定義し Provider のコンストラクタへパラメータを引き渡す処理を記述しなければならない。マスタークラスは、プロバイダ

が包含する実装クラスとアルゴリズム名を結合するプロパティを保有する。プロパ

ティは java.util.Propertiesと同様に扱うことができる。 プロパティのキーは、提供する機能によってプレフィックスが規定されており、

表 5-1のようになっている。 Signature.MD2/RSA=jp.co.fujixerox.security.RSA.MD2Signature

Signature.MD4/RSA=jp.co.fujixerox.security.RSA.MD4Signature

Signature.MD5/RSA=jp.co.fujixerox.security.RSA.MD5Signature

Signature.SHA1/RSA=jp.co.fujixerox.security.RSA.SHA1Signature

Signature.X9.42-DH=jp.co.fujixerox.security.DH.X942Signature

Alg.Alias.Signature.MD2WithRSA=MD2/RSA

Alg.Alias.Signature.MD4WithRSA=MD4/RSA

Alg.Alias.Signature.MD5WithRSA=MD5/RSA

Alg.Alias.Signature.SHA1WithRSA=SHA1/RSA

Alg.Alias.Signature.DH=X9.42-DH

図 5-4 プロバイダの登録データの一部

基本的なフォーマットは

Page 57: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

51

<プレフィックス>.アルゴリズム名=実装クラス名

の形態であり、アルゴリズム名に別名を付ける場合は Alg.Alias.<プレフィックス>.別名=アルゴリズム名 とする。実装クラスの名前はパッケージ名を含めた名前を指定する。

表 5-1 プレフィックスと提供機能

プレフィックス 参照クラス

MessageDigest 指定データのメッセージダイジェスト(ハッシュ)の計算に使用。

Signature デジタル署名の署名および検証に使用。

KeyPairGenerator 指定のアルゴリズムに適合した、公開鍵、非公

開鍵ペアの生成に使用。

KeyFactory Key 型の不透明な暗号化鍵を「鍵仕様」(基本となるキーデータの透明な表現) に変換または逆変換を行うために使用。

KeyStore

「キーストア」の作成および管理に使用。 キーストアは、鍵のデータベースである。キー

ストア内の非公開鍵には、鍵に関連した証明連

鎖がある。証明連鎖は、対応する公開鍵を認証

する。また、キーストアには、信頼できるエン

ティティからの証明書も格納されている。

CertificateFactory 公開鍵の証明書および証明書の取り消しリス

ト (CRL) の作成に使用。

AlgorithmParameters パラメータの符号化および復号化など、特定の

アルゴリズムのパラメータ管理に使用。

AlgorithmParameterGenerator

特定のアルゴリズムに適したパラメータセッ

トの生成に使用。

SecureRandom 乱数または擬似乱数の生成に使用。

Cipher 暗号化および復号の機能を提供する。

ExemptionMechanism 除外機構の機能と、「鍵の回復」、「鍵の弱化」、

および「鍵の預託」の機能を提供する。

KeyAgreement 鍵の交換プロトコルの機能を提供する。

KeyGenerator 鍵ジェネレータの機能を提供する。

Mac MAC(Message Authentication Code)アルゴリズムの機能を提供する。

SecretKeyFactory 秘密鍵のファクトリを表す。

Page 58: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

52

これらのデータは load()メソッドまたは put()メソッドによりマスタークラス

へ記録されなければならない。どちらを使うかは使用者の判断に任せられる。 load()メソッドを使用する場合、入力ストリームを取得するのに

ClassLoader.getSystemResourceAsStream() メ ソ ッ ド や

getResourceAsStream()メソッドを利用すると考えられるが、適切なファイル

が対象になっていることを確認すべきであろう。確認の方法は ProtectionDomain等を利用することになると思うが、詳細は、実装者の判断に任せたい。 マスタークラスに登録されたデータは、各フレームワークの getInstance()メ

ソッドが参照し、フレームワークが実装クラスのインスタンスを作成する。この時、

フレームワークが実装の認証を必要とする場合は、実装を収納するアーカイブに対

して署名の検証を行う。これは暗号処理などにバックドアを設けさせないための機

構であり、マスタークラスと実装クラスの対応を強固にし、悪意ある実装でオーバ

ライドさせないための機構でもある。 この電子署名は X.509 DSA 公開鍵証明書を用いて行われ、発行元は Sun

microsystems 社である。また、この証明書を検証する場合に使用されるトラストアンカは Sun microsystems社と IBM社のものが使用される。 なお、アーカイブを署名するのに使用される証明書を取得する方法は「Java 暗

号化拡張機能用プロバイダの実装方法」を参照して欲しい。 プロバイダが包含する実装クラスは、SPIを実装しなければならない。 通常、SPIは抽象クラスであるので各 SPIを継承し、以下の制限事項を満たすものでなければならない。 通常、engine で始まるメソッド名を持つ抽象メソッドを全て実装しなけれ

ばならない。 引数を持たないコンストラクタを用意しなければならない。

Javaではコンストラクタを定義しなければ、引数を取らないコンストラクタが自動生成されるが、SPI クラスがコンストラクタを引数として要求する場合は、実装クラスで引数なしコンストラクタを定義しなければならない。 これは Class.newInstance()メソッドによってインスタンスの生成が出

来なければならないことを意味している。 実装クラスは、JCEを通さずに利用出来なくするために、finalと宣言されたクラスでなければならない。 また、プロバイダパッケージ外からアクセスできないように、パッケージ独

自のスコープを保持する必要がある。 SPI クラス(実装クラス)はエンジンクラスによりコントロールされ、各フレームワークで共通のステート管理やコンビニエンスメソッドの管理下に置かれる。 特に、JCEで利用するプロバイダの場合、オプショナルな機能として以下のものを提供可能になっている。 CipherSpi.engineWrap()メソッドと CipherSpi.engineUnwrap()メ

Page 59: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

53

ソッドこれらのメソッドは安全な鍵移送を目的とした機能である。必ずしも

提供する必要は無い。 ひとつ以上の免責機構の提供 免責機構には「鍵復元」「鍵預託」「鍵弱化」が用意されており、これらの機

能を提供することにより、クライアントアプリケーションの機能制限を緩め

ることが可能となる。 これらの機能を JCE自身が積極的に利用することは無い。しかし、これはアプリケーション側からみると、存在するか不明な機能となるので、アプリケーションは

この機能が必ず存在すると言う前提をもってはいけない。プロバイダを実際に利用

可能となるためには、プロバイダを Securityクラスへ登録しなければならない。プロバイダの登録には動的に行う方法と静的に行う方法の 2種類が提供されている。 どちら方法を利用してもアプリケーションプログラムの変更は必要無い。 動的に登録する場合 マスタークラスのインスタンスを生成し、Java.security.SecurityのメソッドaddProvider()メソッド、及び、insertProviderAt()メソッドを呼び出

し登録する。 静的に登録する場合

${Java_HOME}/jre/lib/security/Java.security へエントリーを追加する。追加方法はテキストエディタなどで当該ファイルを編集することによって行う。

編集内容は図 5-5のようになる。 #

# List of providers and their preference orders (see above):

#

security.provider.1=Sun microsystems.security.provider.Sun

security.provider.2=com.sun.net.ssl.internal.ssl.Provider

security.provider.3=com.sun.rsajca.Provider

security.provider.4=com.sun.crypto.provider.Sun microsystemsJCE

security.provider.5=sun.security.jgss.SunProvider

security.provider.6=org.jnsa.ChallengePKI2003.Example6.MasterClass

#

# Select the source of seed data for SecureRandom. By default an

図 5-5 JDK 1.4 の場合の Java.security の編集例

図 5-5 で は 、 優 先 度 6 の プ ロ バ イ ダ の マ ス タ ー ク ラ ス と し て

org.jnsa.ChallengePKI2003.Example6.MasterClassを登録している。 優先度とはシステムへ登録されているプロバイダの 6番目であることを意味して

Page 60: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

54

おり、実装の検索は優先度 1から順番に行われる。また、この番号付けは間があいてはならず、登録状況によって番号を変えなければならない。

実際にフレームワークが実装の検索を行う様子を知りたい場合、実装例

Example6 の MasterClass.Java へ getProperty()メソッドを図 5-6のように追加してパラメータ等を表示する事により確認できる。

public String getProperty(String key) {

(new RuntimeException()).printStackTrace();

System.out.println(“Find implementation using “ + key);

return super.getProperty(key);

}

図 5-6 挙動観察用メソッド例

特に、JCEは認証された実装を必要とするので、プロバイダを収納するアーカイブには署名をしなければならない。署名に必要なものは署名に使用する証明書と

jarsignerと言う JDKに含まれるツールである。手順は以下のようになる。 1. マスタークラスと実装クラスをまとめたアーカイブを作成する。 2. jarsignerを使用し、アーカイブへ署名する アーカイブの作成は、普通に jar 等を利用して作成する。MANIFEST の作成や圧縮の有無は特に気にする必要は無い。

jarsignerを使って署名するには図 5-7のコマンドラインを指定する。

% jarsigner アーカイブパス名 鍵のエイリアス名

図 5-7 jarsigner の利用方法

指定する鍵のエイリアス名は、キーストア中に存在するものを指定する。デフォ

ルトのキーストア以外に鍵を置いてある場合、コマンドラインへオプション

-keystoreを追加し、明示的に指定する必要がある。 なお、キーストアの用意や証明書の用意に関しては「Java 暗号化拡張機能用プロバイダの実装方法」を参照して欲しい。

Page 61: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

55

6 まとめ

Javaが提供しているセキュリティ関連機能は、総じてプリミティブであり、低位規格を実装する分には問題にならない。また、X.509 証明書から一部の V3 拡張データなどを取り出す場合や、PKCS #7(CMS)から公開鍵証明書や CRLを取り出すなどの、一部の高位規格に関する実装も持っている。しかし、コアクラスがサポ

ートしている範囲外のデータにアクセスする場合(PKCS #7で、SignedDataのdataコンテンツへアクセスするなど)、実装が包含しているであろう機能すらアプリケーションからは使用できず、前提になる機能をで実装する必要がある。事実、複数の

プロバイダで ASN.1に関する実装が包含されている。 この問題はフレームワークの構成上の問題であり、中位/低位クラスの規格に関するフレームワークが不足している点に問題があると考えられる。この問題を解決す

るために、用意すべきフレームワークを列挙してみる。 1. ASN.1に関するフレームワーク 最低限 DER/BER/CER エンコードされているデータの入出力に関するフレームワークが必要である。入力だけでも用意されていれば、上位の規格を

サポートするための大きな足がかりになる。 2. PKCS#7(CMS)のプリミティブなフレームワーク 署名関連を見た場合、BIT STRINGへ収納できるデータだけでも貴重であるが。ある程度の規模をもつ規格の場合は、PKCS #7を要求するものが多い。 現在の JCE を用いれば CertificateFactory が SignedData の certificatesや crls へアクセスできるが、signerInfo や contentInfo へアクセスできることはもっと重要である。

3. 高位の暗号/署名に関するフレームワークのサポート CMSをサポートするフレームワークは、さまざまなアプリケーションを作成する上で有用である。本来であれば CMS が行えるオペレーション全てをサポートしていることが望ましいが、当面は暗号と署名に関する上位フレー

ムワークがあれば需要は満たせると考える。 ここに挙げたようなフレームワークは JSR26-74 で提案され、仕様策定グループ

が形成されているようだが、公的な活動記録の最終日時が 2001/01/05となっているので、実質解散していると考える余地があるが、PKCS #1の機能強化や RSA鍵に対するインターフェイス拡張などを見ると、Sun microsystems 自体は活動を継続しているのかもしれない。今後の活動に期待したい。 26 JSR(Java Specification Requests)とは Javaの新規・改定仕様を提案するためのプロセスである。運用はJCP(Java Community Process)を用いて行われる。また JCPは一般から参加可能なオープンな組織である。

Page 62: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

56

7 参考文献

[ASN1] ASN.1 Standard、http://asn1.elibel.tm.fr/en/standards/index.htm [DSS] DIGITAL SIGNATURE STANDARD (DSS) 、

http://www.itl.nist.gov/fipspubs/fip186.htm [PKCS] PKCS#1/5/7/8/12、http://www.rsasecurity.com/rsalabs/pkcs/ [J2SE14] Java 2 Platform, Standard Edition, 1.4.0 API仕様、

http://Java.sun.com/j2se/1.4/ja/docs/ja/api/index.html [JCA] Java 暗号化アーキテクチャ API の仕様およびリファレンス、

http://Java.sun.com/j2se/1.4/ja/docs/ja/guide/security/CryptoSpec.html [JPATH] Java Certification Path API プログラマーズガイド、

http://Java.sun.com/j2se/1.4/ja/docs/ja/guide/security/certpath/CertPathProgGuide.html

[JCProv] Java 暗号化拡張機能用プロバイダの実装方法、 http://Java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jce/HowToImplAJCEProvider.html

[JCE] Java 暗号化拡張機能 (JCE) リファレンスガイド、 http://Java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jce/JCERefGuide.html

[RFC1310] RFC 1310 - The MD2 Message-Digest Algorithm、 http://www.ietf.org/rfc/rfc1319.txt

[RFC1321] RFC 1321 - The MD5 Message-Digest Algorithm、 http://www.ietf.org/rfc/rfc1321.txt

[RFC2104] RFC 2104 - HMAC: Keyed-Hashing for Message Authentication、 http://www.ietf.org/rfc/rfc2104.txt

[RFC2440] RFC 2440 - OpenPGP Message Format、 http://www.ietf.org/rfc/rfc2440.txt

[RFC2692] RFC 2692 - SPKI Requirements、http://www.ietf.org/rfc/rfc2692.txt [RFC2693] RFC 2693 - SPKI Certificate Theory、http://www.ietf.org/rfc/rfc2693.txt [RFC3174] RFC 3174 - US Secure Hash Algorithm 1 (SHA1) 、

http://www.ietf.org/rfc/rfc3174.txt [RFC3280] RFC 3280 - Internet X.509 Public Key Infrastructure Certificate and

Certificate Revocation List (CRL) Profile、 http://www.ietf.org/rfc/rfc3280.txt

[SECAPI1] 平成 15年度 情報処理振興事業協会 「セキュリティ APIに関する技術調査:- Part 1 - 概要 アーキテクチャ・機能・暗号技術とアルゴリズム」

Page 63: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

57

8 用語(参考)

API Application Program Interfaceの略。 あるプラットフォーム(OSやミドルウェア)向けのソフトウェアを開発する際に使用できる命令や関数の集合のこと。個々の開発者は規約に従ってその

機能を「呼び出す」だけで、自分でプログラミングすることなくその機能を

利用したソフトウェアを作成することができる。 DER/BER/CER ASN.1が利用するデータのエンコーディング規約。 それぞれ細部が異なるエンコーディングであるが、本質的には同じものと

判断してよい。形式はバイナリであり、ヘッダとコンテンツを単位としてエ

ンコーディングを行う。 また、XER(XML Encoding Rules)というエンコーディングも規定されているが、こちらは XML をベースにしたエンコーディングであり、これらのものとは互換性は存在しない。

DSA Digital Signature Algorithm の略。DSAとは電子署名の方式のひとつであり、NISTの FIPS 186により規定されている。

FIPS 米国連邦政府調達品に強制力をもつ標準。民間を拘束しないがその影響力

は非常に大きい。 JDK Java Development Kitの略で、Javaでの開発のために必要な、コンパイラなどのツール群と実行環境を含む。

PGP(Pretty Good Privacy) PGP は Philip R. Zimmermann 氏が開発した暗号ソフトウェアであり、RSAと DH/DSSの 2つのアルゴリズムを実装している。 アメリカは PGPに用いられている暗号技術を武器とみなし、外国への輸出を 1999年まで禁止していた。そのため、アメリカで作られた PGPをアメリカ国外で使うことが出来なかった。そのために PGPのソースコードを印刷してそれを持ち出すことによって「国際版」が作られた。 国際版はノルウェーの Stale Schumacher 氏によって開発、配布された(http://www.pgpi.org/)。しかし、1999年 12月 13日にアメリカからの PGPの輸出が一部の国を除いて可能になり、アメリカ国外でも合法的に US 版PGPを使用できるようになったため、国際版の開発は終了した。 2001年 10月に PGPの開発元である Network Associates社が PGP部門

Page 64: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

58

の解体を発表、売却先を探していたが売却先が見つからないまま 2002 年 3月に PGPの発売を停止した。 現在は、フリー版である PGP6.5.8cktのみ開発が継続している。

PKCS RSA Laboratories 社を中心として策定している規格で、Public-Key Cryptography Standardsの頭文字をとったものである。もともとは RSA等の公開鍵を利用するための各種規格であったが、現在では、公開鍵や暗号を

取り巻く一連の規格群になっている。 RFC Request For Commentの略。主に、ネットワーク上で動作するサービスやアプリケーションの仕様を定義したり、データのフォーマットを定義したり

している。 仕様以外に、インターネットの使い方やマナーについて言及しているもの

もある。 RSA暗号 三人の開発者(Rivest、Shamir、Adelman)の頭文字を取った公開鍵系の暗号アルゴリズム。

SPKI(Simple Public Key Infrastructure) IETFの SPKI-WGで規格化されたテキストベースの公開鍵基盤。 主な目的は、あるアクションを認証し、許可を与え、能力を認定すること

などである。 初期のものは鍵と保有者の対に各種属性を付与したものを証明書とし、証

明書の検証は特に必要がなかった。 クラスローダー 実行コードであるクラスのバイトコードを読み取り、VM 内へ配置する機

能。 サンドボックス 保護された領域内でプログラムを動作させることで、その外へ悪影響が及

ぶのを防止するセキュリティモデル。 このモデルでは、外部から受け取ったプログラムを保護された領域に閉じ

込め、動作させる。この領域は他のファイルやプロセスからは隔離され、内

部から外界を操作することに制限が掛けられている。 このため、そのプログラムが暴走/悪意あるコードが実行されても、外に

あるデータなどに影響を与えることはない。 バッファオーバラン プログラムは、作業の目的に合わせてメモリの割り当てを受ける。この領

域は他の目的のために割り当てられた領域と隣接している可能性があるので、

その範囲を逸脱して使用するようなことはしてはならない。

Page 65: セキュリティ API に関する技術調査 · 擬似乱数は、周期性を有していたり、 分布に偏りがある擬似乱数であり、本物の乱数ではない13。周期の長さや分布

59

しかし、プログラムに不具合がある場合、この領域を逸脱してデータへア

クセスする場合がある。この現象が発生すると隣接した領域を破壊し、プロ

グラムが想定不能な動作を行う場合がある。 また、この破壊を意図的に発生させ、任意のコードを実行させることも不

可能ではない。 この不具合は、ワームがシステムに進入する場合などに利用しており、重

大なセキュリティホールにもなる。 プラグイン 機能拡張行うための外部プログラム。拡張される対象により内容はさまざ

まだが、ブラウザなどがこの機能を有している。 プロバイダ ソフトウェアにおけるプロバイダとは、一般的にはある特定のインターフ

ェイスに対し、実際の機能を提供するソフトウェア群を指す。各種プラグイ

ンなどもこの形態を持つものが多い。 メモリーリーク メモリはシステム中の重要なリソースであり、有限なリソースでもあるの

で、その利用法は厳密に管理される必要がある。その管理は、カーネルやメ

モリマネージャが行っており、一般のプログラムは管理主体に割り当て要求

を出すことによって、利用が可能になる。 プログラムは必要に応じてメモリの割り当てを要求し、不要になれば返却

するのが一般的なアプリケーション動作である。 しかし、プログラムが不要なメモリを返却せず、割り当て要求だけを出し

続けた場合、メモリの割り当てが出来なくなる。この場合、返却可能なメモ

リを放置する側に問題があり、時間と共にプロセスが肥大化してゆく。 なお、このようなプログラムを放置しておくと、システム全体がリソース

不足に陥り、異常終了や不正動作が発生し正常に稼動できなくなる。 免責機構 法律により利用が制限されている機能を合法的に使用するためのメカニズ

ム。国によりどのような制限が課されるかさまざまであるが、暗号の場合は

鍵預託などで制限が解除される場合がある。 リポジトリ 物品を安全に保管しておく場所。ソフトウェア関係でいう場合はデータの

保管場所を意味している。 ワッセナー協約 ココムに代わる新ココム体制の下で、武器輸出の新しい管理体制として

1996年 7月に成立した規制協約の名称


Recommended