Java の MessageDigest クラスは、MD5 あるいは SHA などのメッセージダイジェストアルゴリズムの機能を提供しています。
以前、bitWalk's: MD5 & SHA Checksum Utility で Windows 上で動作する MD5 & SHA Checksum Utility を紹介しましたが、Java で同じようなことを実現してみようと思い、簡単なサンプルを JavaFX で作ってみました。なお、MessageDigest クラスの使い方は、参考サイト [1] を参考にさせていただきました。
動作を確認した環境は次の通りです。
- OS: Fedora 23 (x86_64)
- Java: Java SE 1.8.0_72 (jdk1.8.0_72-1.8.0_72-fcs.x86_64)
- IDE: NetBeans IDE 8.1
サンプルプログラムを以下に示しました。参考サイト [2] の GitHub にイメージを含む全ソースをアップしてあります。
package hashcalc; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; import javafx.stage.FileChooser; import javafx.stage.Stage; import javax.xml.bind.DatatypeConverter; public class HashCalc extends Application { String baseDir = getClass().getResource("image/").toString(); Image icoApp = new Image(baseDir + "Binary.png"); Image icoFile = new Image(baseDir + "File.png"); Image icoPen = new Image(baseDir + "Pencil.png"); File file; TextField field_sha256; @Override public void start(Stage primaryStage) { BorderPane root = new BorderPane(); Scene scene = new Scene(root); GridPane gridpane = new GridPane(); gridpane.setPadding(new Insets(5)); gridpane.setHgap(5); gridpane.setVgap(2); ColumnConstraints column1 = new ColumnConstraints(); ColumnConstraints column2 = new ColumnConstraints(600); ColumnConstraints column3 = new ColumnConstraints(); gridpane.getColumnConstraints().addAll(column1, column2, column3); RowConstraints row1 = new RowConstraints(); row1.setFillHeight(true); RowConstraints row2 = new RowConstraints(); row2.setFillHeight(true); gridpane.getRowConstraints().addAll(row1, row2); // File Name label Label label_file = new Label("File Name"); GridPane.setHalignment(label_file, HPos.RIGHT); gridpane.add(label_file, 0, 0); // File Name field TextField field_file = new TextField(); field_file.setEditable(false); GridPane.setHalignment(field_file, HPos.LEFT); gridpane.add(field_file, 1, 0); // File Name button Button button_file = new Button(); button_file.setGraphic(new ImageView(icoFile)); button_file.setOnAction((ActionEvent t) -> { FileChooser fileChooser = new FileChooser(); file = fileChooser.showOpenDialog(primaryStage); field_file.setText(file.toString()); clearMessageDigest(); }); gridpane.add(button_file, 2, 0); // SHA-256 label Label label_sha256 = new Label("SHA-256"); GridPane.setHalignment(label_sha256, HPos.RIGHT); gridpane.add(label_sha256, 0, 1); // SHA-256 field field_sha256 = new TextField(); field_sha256.setEditable(false); GridPane.setHalignment(field_sha256, HPos.LEFT); gridpane.add(field_sha256, 1, 1); // SHA-256 button Button button_sha256 = new Button(); button_sha256.setGraphic(new ImageView(icoPen)); button_sha256.setOnAction((ActionEvent t) -> { try { String md = calcMessageDigest("SHA-256"); field_sha256.setText(md); } catch (NoSuchAlgorithmException | IOException ex) { Logger.getLogger(HashCalc.class.getName()).log(Level.SEVERE, null, ex); } }); gridpane.add(button_sha256, 2, 1); root.setCenter(gridpane); primaryStage.setResizable(false); primaryStage.setTitle("HashCalc"); primaryStage.getIcons().add(icoApp); primaryStage.setScene(scene); primaryStage.show(); } void clearMessageDigest() { field_sha256.setText(""); } String calcMessageDigest(String algorithm) throws NoSuchAlgorithmException, FileNotFoundException, IOException { if (isEmpty(file)) { return ""; } if (!checkBeforeReadfile(file)) { return ""; } MessageDigest md = MessageDigest.getInstance(algorithm); FileInputStream in = new FileInputStream(file); byte[] dataBytes = new byte[1024]; int nread = 0; while ((nread = in.read(dataBytes)) != -1) { md.update(dataBytes, 0, nread); } byte[] mdbytes = md.digest(); return DatatypeConverter.printHexBinary(mdbytes); } boolean isEmpty(File value) { return value == null || value.length() == 0; } static boolean checkBeforeReadfile(File read) { if (read.exists()) { if (read.isFile() && read.canRead()) { return true; } } return false; } public static void main(String[] args) { launch(args); } }
実行例
試しに、Fedora 23 の Live-CD のイメージを使ってみましたが、まあ許容できる時間で結果を返してくれます。本格的なユーティリティプログラムとして使うには、もう少し GUI を作りこむ必要がありそうです。
参考サイト