メッセージダイジェスト

Since: May/23rd/2004

電子署名

ポリシファイルによるコードのアクセス制御について説明してきました。ここからは、データの保全性を保証するための仕組みを説明します。データに署 名することで、送信者の本人性とデータ改竄がされていない完全性を保証する仕組みを提供し、コードに署名することで、ポリシファイルに記述されたアクセス 制御を適用します。

メッセージダイジェスト

メッセージダイジェストは、データが改竄されていないことを保証するために使います。データのバイト列から算出されるハッシュコードであり、データ が改竄されると算出されるダイジェストも変更されます。ダイジェストと送信されたデータから算出したものが異なれば、途中で改竄されたことが確実になりま す。

ダイジェストを取得するためには、抽象クラス java.security.MessageDigest を使います。getInstance() によって生成されたオブジェクトは、update() によってダイジェストを算出するデータを受け取り、digest() を呼び出すことによりダイジェストのバイト列を得ます。得られたバイト列は、isEqual() によって等価性を比較できます。

ダイジェストするデータは、update() の引数に直接バイト列を与える他、java.security.DigestOutputStream, DigestInputStream によって、ラップしたストリームに対する入出力を通して暗黙的に update() にデータを与えることができます。

リスト1は、メッセージダイジェストの算出アルゴリズムに SHA1 (Secure Hash Algorithm 1) を指定した例です。指定できるアルゴリズム名については、Sunのドキュメントを参照してください。

リスト1. MessageDigestの利用 (MessageDigestDemo.java)

import java.security.*;
import java.io.*;

class DigestImpl {
	// メッセージダイジェストを保持するバイト配列
	byte[] orgDigest;
	/**
	 * 出力ストリームを通してダイジェストを計算
	 * @param msg     	出力するデータ
	 * @param alg     	メッセージダイジェストアルゴリズム
	 * @param filename	出力ファイル名
	 */
	void initDigest(String msg, String alg, String filename) {
		try {
			// MessageDigestオブジェクトの初期化
			MessageDigest md = MessageDigest.getInstance(alg);
			FileOutputStream fout = new FileOutputStream(filename);
			// ダイジェスト取得用の出力ストリーム
			DigestOutputStream dout = new DigestOutputStream(fout, md);
			ObjectOutputStream oout = new ObjectOutputStream(dout);
			oout.writeObject(msg);    // 暗黙的にupdate()が起動
			dout.on(false);    // ダイジェストストリームをオフ
			orgDigest = md.digest();    // ダイジェストの取得
			printDigest(orgDigest);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	/**
	 * 入力ストリームを通してダイジェストを計算し、等価性をチェック
	 * @param alg     	メッセージダイジェストアルゴリズム
	 * @param filename	出力ファイル名
	 */
	void validateDigest(String alg, String filename) {
		try {
			// MessageDigestオブジェクトの初期化
			MessageDigest md = MessageDigest.getInstance(alg);
			FileInputStream fin = new FileInputStream(filename);
			// ダイジェスト取得用の入力ストリーム
			DigestInputStream din = new DigestInputStream(fin, md);
			ObjectInputStream oin = new ObjectInputStream(din);
			Object message = oin.readObject();    // 暗黙的にupdate()が起動
			din.on(false);    // ダイジェストストリームをオフ
			byte[] calcDigest = md.digest();
			printDigest(calcDigest);
			// ダイジェストの検証
			if (MessageDigest.isEqual(orgDigest, calcDigest)) {
				System.out.println("This message is valid.");
			} else {
				System.out.println("This message is invalid.");
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	/**
	 * バイト配列を得て文字列に変換して出力
	 * @param digest ダイジェスト
	 */
	void printDigest(byte[] digest) {
			StringBuffer dec = new StringBuffer("");
			for (int i = 0; i < digest.length; i++) {
				int val = digest[i] & 0xFF;
				if (val < 16) {
					dec.append("0");
				}
				dec.append(Integer.toString(val, 16)).append(" ");
			}
			System.out.println(dec.toString());
	}
}

class MessageDigestDemo {
	public static void main(String[] args) {
		String message = "This is message digest demo.",
		    alg = "SHA1", filename = "message.txt";
		DigestImpl digest = new DigestImpl();
		digest.initDigest(message, alg, filename);
		digest.validateDigest(alg, filename);
	}
}

リスト2. リスト1の実行結果

>java MessageDigestDemo
48 5b 03 45 5b 38 19 f8 f7 84 d2 0e 81 8c 8f 2a 26 89 35 1c
48 5b 03 45 5b 38 19 f8 f7 84 d2 0e 81 8c 8f 2a 26 89 35 1c
This message is valid.


Copyright © 2004 SUGAI, Manabu. All Rights Reserved.
SEO [PR] !uO z[y[WJ Cu