いがぴょん画像(小) 2003/06

2002/12/13 日記: ファイルのMD5値を求めるサンプル

[いがぴょんの日記v2,diary,igapyon] Javaで入力ファイルのMD5値を求めるサンプルを作成してみました。

広告: BlancoEclipseDistribution 最新安定版 (3.5.0-20090708) リリース 07/16
最新版の Eclipse である Eclipse Classic (SDK) 3.5.0 一式 (日本語化済み) が Windowsインストーラを用いてインストールできます。
BlancoEclipseDistribution は Eclipseディストリビューションのひとつに該当します。

インディックスページへ戻る
MD5取得サンプル

ファイルのMD5値を求めるサンプルプログラム

MyDigest.java
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MyDigest {
    private static final String FILENAME = "aaa.txt";
    public static void main(String[] args) {
        try {
            DigestInputStream inStream =
                new DigestInputStream(
                    new BufferedInputStream(
                        new FileInputStream(FILENAME)),
                    MessageDigest.getInstance("MD5"));
            byte[] buf = new byte[1024];
            for (;;) {
                if (inStream.read(buf) <= 0)
                    break;
            }
            inStream.close();

            MessageDigest md5 = inStream.getMessageDigest();
            byte[] digest = md5.digest();
            System.out.print("[" + FILENAME + "] のMD5は [");
            for (int loop = 0;loop < digest.length;loop++) {
                System.out.print(
                    Integer.toHexString(0xff&(char)digest[loop]));
            }
            System.out.println("] です。");
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
    }
}

なんのことはないコーディングなのですが、いざサンプルを探そうとしたらちょっと手こずりました。


結城浩さんのツッコミ
Subject: [igapyon:01082] MD5 サンプル


結城です。細かい突っ込みです。

いがぴょんさんのMD5を求めるサンプルで、
16進表示を行う以下の部分には小さなバグがあります。

    System.out.print(
        Integer.toHexString(0xff&(char)digest[loop]));

このままですと、16未満の数が一桁になってしまいます。
たとえば、

012

という3バイトからなるファイルの正しいMD5値は、

D2490F048DC3B77A457E3E450AB4EB38

なのですが、これが、

d249f48dc3b77a457e3e45ab4eb38

のように短くなってしまいます。
一バイトごとに空白をあけてみると、原因がわかります。

d2 49 f 4 8d c3 b7 7a 45 7e 3e 45 a b4 eb 38

修正としてはたとえば、

    int n = digest[loop] & 0xFF;
    if (n <= 0xF) {
        System.out.print("0");
    }
    System.out.print(Integer.toHexString(n));

のようにします。もっとうまい方法があるかも…。
MD5を求めるプログラムの本質的なところではありませんけれど、
ちょっと気になったのでご報告します。

あ、それから、

0xff&(char)digest[loop]

でcharにキャストしているのはなぜでしょう。
もしもunsignedのこころでしたら、0xffでマスクをしているので、intの符号ビットは落ちているのですから、キャストは不要ではないかと思います。

サンプル

Sample.java
class Sample {
    public static void main(String[] args) {
        byte a =  1;
        byte b = -1;
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("a & 0xFF = " + (a & 0xFF));
        System.out.println("b & 0xFF = " + (b & 0xFF));
    }
}

実行結果

a = 1
b = -1
a & 0xFF = 1
b & 0xFF = 255

現在、結城は暗号本を書いているので、

似たようなコードを書いております。参考まで。
私のはDigestInputStreamも使わず、バッファリングもせず、1バイトずつupdateしていますが(^_^;

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

public class Digest {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.out.println("Usage: java Digest inputfilename");
            System.exit(0);
        }
        String filename = args[0];
        System.out.println("filename = " + filename);

        MessageDigest sha = MessageDigest.getInstance("SHA");
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        
        DataInputStream in = new DataInputStream(new FileInputStream(filename));
        try {
            while (true) {
                byte b = in.readByte();
                sha.update(b);
                md5.update(b);
            }
        } catch (EOFException ignore) {
        }
        in.close();

        System.out.println("SHA =" + toHexString(sha.digest()));
        System.out.println("MD5 =" + toHexString(md5.digest()));
    }
    private static String toHexString(byte[] buf) {
        String s = "";
        for (int i = 0; i < buf.length; i++) {
            int n = buf[i] & 0xff;
            if (n < 16) {
                s += " 0";
            } else {
                s += " ";
            }
            s += Integer.toHexString(n).toUpperCase();
        }
        return s;
    }
}

◆実行結果

> type input.txt
012
> java Digest input.txt
filename = input.txt
SHA = C4 A2 D9 9B C2 8D 23 60 98 A0 95 27 7B 7E B0 71 8D 6B E0 68
MD5 = D2 49 0F 04 8D C3 B7 7A 45 7E 3E 45 0A B4 EB 38

ここからいがぴょん
…MLから未転載… もといMLに返信する前に 出張に旅立ちました (苦笑)

Eclipse.orgに接続できない件

昨日 Eclipse.orgへの接続が怪しかったですが、これは eclipse.orgのDNSが異常だったのが原因だったとのことです。(と www.eclipse.orgに書いてありました)

世間のニュースから (RSS) 2002

いがぴょんについて
Last modified: $Date: 2009/08/25 09:37:41 $