2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.util
;
19 import java
.io
.FileInputStream
;
20 import java
.io
.IOException
;
21 import java
.io
.InputStream
;
22 import java
.nio
.ByteBuffer
;
23 import java
.nio
.channels
.FileChannel
;
24 import java
.nio
.channels
.FileChannel
.MapMode
;
25 import java
.nio
.file
.Files
;
26 import java
.nio
.file
.Path
;
27 import java
.security
.MessageDigest
;
28 import java
.security
.NoSuchAlgorithmException
;
30 /** Utilities around cryptographic digests */
31 public class DigestUtils
{
32 public final static String MD5
= "MD5";
33 public final static String SHA1
= "SHA1";
34 public final static String SHA256
= "SHA-256";
35 public final static String SHA512
= "SHA-512";
37 private static Boolean debug
= false;
38 // TODO: make it writable
39 private final static Integer byteBufferCapacity
= 100 * 1024;// 100 KB
41 public static byte[] sha1(byte[] bytes
) {
43 MessageDigest digest
= MessageDigest
.getInstance(SHA1
);
45 byte[] checksum
= digest
.digest();
47 } catch (Exception e
) {
48 throw new UtilsException("Cannot SHA1 digest", e
);
52 public static String
digest(String algorithm
, byte[] bytes
) {
54 MessageDigest digest
= MessageDigest
.getInstance(algorithm
);
56 byte[] checksum
= digest
.digest();
57 String res
= encodeHexString(checksum
);
59 } catch (Exception e
) {
60 throw new UtilsException("Cannot digest with algorithm " + algorithm
, e
);
64 public static String
digest(String algorithm
, InputStream in
) {
66 MessageDigest digest
= MessageDigest
.getInstance(algorithm
);
67 // ReadableByteChannel channel = Channels.newChannel(in);
68 // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity);
69 // while (channel.read(bb) > 0)
71 byte[] buffer
= new byte[byteBufferCapacity
];
73 while ((read
= in
.read(buffer
)) > 0) {
74 digest
.update(buffer
, 0, read
);
77 byte[] checksum
= digest
.digest();
78 String res
= encodeHexString(checksum
);
80 } catch (Exception e
) {
81 throw new UtilsException("Cannot digest with algorithm " + algorithm
, e
);
83 StreamUtils
.closeQuietly(in
);
87 public static String
digest(String algorithm
, File file
) {
88 FileInputStream fis
= null;
89 FileChannel fc
= null;
91 fis
= new FileInputStream(file
);
92 fc
= fis
.getChannel();
94 // Get the file's size and then map it into memory
95 int sz
= (int) fc
.size();
96 ByteBuffer bb
= fc
.map(FileChannel
.MapMode
.READ_ONLY
, 0, sz
);
97 return digest(algorithm
, bb
);
98 } catch (IOException e
) {
99 throw new UtilsException("Cannot digest " + file
+ " with algorithm " + algorithm
, e
);
101 StreamUtils
.closeQuietly(fis
);
105 } catch (IOException e
) {
111 protected static String
digest(String algorithm
, ByteBuffer bb
) {
112 long begin
= System
.currentTimeMillis();
114 MessageDigest digest
= MessageDigest
.getInstance(algorithm
);
116 byte[] checksum
= digest
.digest();
117 String res
= encodeHexString(checksum
);
118 long end
= System
.currentTimeMillis();
120 System
.out
.println((end
- begin
) + " ms / " + ((end
- begin
) / 1000) + " s");
122 } catch (NoSuchAlgorithmException e
) {
123 throw new UtilsException("Cannot digest with algorithm " + algorithm
, e
);
127 public static String
sha1hex(Path path
) {
128 return digest(SHA1
, path
, byteBufferCapacity
);
131 public static String
digest(String algorithm
, Path path
, long bufferSize
) {
132 byte[] digest
= digestRaw(algorithm
, path
, bufferSize
);
133 return encodeHexString(digest
);
136 public static byte[] digestRaw(String algorithm
, Path file
, long bufferSize
) {
137 long begin
= System
.currentTimeMillis();
139 MessageDigest md
= MessageDigest
.getInstance(algorithm
);
140 FileChannel fc
= FileChannel
.open(file
);
141 long fileSize
= Files
.size(file
);
142 if (fileSize
<= bufferSize
) {
143 ByteBuffer bb
= fc
.map(MapMode
.READ_ONLY
, 0, fileSize
);
146 long lastCycle
= (fileSize
/ bufferSize
) - 1;
148 for (int i
= 0; i
<= lastCycle
; i
++) {
150 if (i
!= lastCycle
) {
151 bb
= fc
.map(MapMode
.READ_ONLY
, position
, bufferSize
);
152 position
= position
+ bufferSize
;
154 bb
= fc
.map(MapMode
.READ_ONLY
, position
, fileSize
- position
);
160 long end
= System
.currentTimeMillis();
162 System
.out
.println((end
- begin
) + " ms / " + ((end
- begin
) / 1000) + " s");
164 } catch (Exception e
) {
165 throw new UtilsException("Cannot digest " + file
+ " with algorithm " + algorithm
, e
);
169 public static void main(String
[] args
) {
172 file
= new File(args
[0]);
174 System
.err
.println("Usage: <file> [<algorithm>]" + " (see http://java.sun.com/j2se/1.5.0/"
175 + "docs/guide/security/CryptoSpec.html#AppA)");
179 if (args
.length
> 1) {
180 String algorithm
= args
[1];
181 System
.out
.println(digest(algorithm
, file
));
183 String algorithm
= "MD5";
184 System
.out
.println(algorithm
+ ": " + digest(algorithm
, file
));
186 System
.out
.println(algorithm
+ ": " + digest(algorithm
, file
));
187 System
.out
.println(algorithm
+ ": " + sha1hex(file
.toPath()));
188 algorithm
= "SHA-256";
189 System
.out
.println(algorithm
+ ": " + digest(algorithm
, file
));
190 algorithm
= "SHA-512";
191 System
.out
.println(algorithm
+ ": " + digest(algorithm
, file
));
195 final private static char[] hexArray
= "0123456789abcdef".toCharArray();
199 * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
200 * -a-hex-string-in-java
202 public static String
encodeHexString(byte[] bytes
) {
203 char[] hexChars
= new char[bytes
.length
* 2];
204 for (int j
= 0; j
< bytes
.length
; j
++) {
205 int v
= bytes
[j
] & 0xFF;
206 hexChars
[j
* 2] = hexArray
[v
>>> 4];
207 hexChars
[j
* 2 + 1] = hexArray
[v
& 0x0F];
209 return new String(hexChars
);