top / index / prev / next / target / source

2002-12-13 diary: ファイルのMD5値を求めるサンプル

いがぴょん画像(小) 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

ファイルのMD5値を求めるサンプル

Javaで入力ファイルのMD5値を求めるサンプルを作成してみました。

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に書いてありました)

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


この日記について