top / index / prev / next / target / source
日記形式でつづる いがぴょんコラム ウェブページです。
Javaで入力ファイルの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のDNSが異常だったのが原因だったとのことです。(と www.eclipse.orgに書いてありました)