]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/DigestUtils.java
Fix issue with CMS deployment marked twice as available when state has
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / DigestUtils.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 package org.argeo.util;
17
18 import java.io.File;
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;
29
30 /** Utilities around cryptographic digests */
31 public class DigestUtils {
32 public final static String SHA1 = "SHA1";
33
34 private static Boolean debug = false;
35 // TODO: make it writable
36 private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB
37
38 public static byte[] sha1(byte[] bytes) {
39 try {
40 MessageDigest digest = MessageDigest.getInstance(SHA1);
41 digest.update(bytes);
42 byte[] checksum = digest.digest();
43 return checksum;
44 } catch (Exception e) {
45 throw new UtilsException("Cannot SHA1 digest", e);
46 }
47 }
48
49 public static String digest(String algorithm, byte[] bytes) {
50 try {
51 MessageDigest digest = MessageDigest.getInstance(algorithm);
52 digest.update(bytes);
53 byte[] checksum = digest.digest();
54 String res = encodeHexString(checksum);
55 return res;
56 } catch (Exception e) {
57 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
58 }
59 }
60
61 public static String digest(String algorithm, InputStream in) {
62 try {
63 MessageDigest digest = MessageDigest.getInstance(algorithm);
64 // ReadableByteChannel channel = Channels.newChannel(in);
65 // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity);
66 // while (channel.read(bb) > 0)
67 // digest.update(bb);
68 byte[] buffer = new byte[byteBufferCapacity];
69 int read = 0;
70 while ((read = in.read(buffer)) > 0) {
71 digest.update(buffer, 0, read);
72 }
73
74 byte[] checksum = digest.digest();
75 String res = encodeHexString(checksum);
76 return res;
77 } catch (Exception e) {
78 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
79 } finally {
80 StreamUtils.closeQuietly(in);
81 }
82 }
83
84 public static String digest(String algorithm, File file) {
85 FileInputStream fis = null;
86 FileChannel fc = null;
87 try {
88 fis = new FileInputStream(file);
89 fc = fis.getChannel();
90
91 // Get the file's size and then map it into memory
92 int sz = (int) fc.size();
93 ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
94 return digest(algorithm, bb);
95 } catch (IOException e) {
96 throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e);
97 } finally {
98 StreamUtils.closeQuietly(fis);
99 if (fc.isOpen())
100 try {
101 fc.close();
102 } catch (IOException e) {
103 // silent
104 }
105 }
106 }
107
108 protected static String digest(String algorithm, ByteBuffer bb) {
109 long begin = System.currentTimeMillis();
110 try {
111 MessageDigest digest = MessageDigest.getInstance(algorithm);
112 digest.update(bb);
113 byte[] checksum = digest.digest();
114 String res = encodeHexString(checksum);
115 long end = System.currentTimeMillis();
116 if (debug)
117 System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
118 return res;
119 } catch (NoSuchAlgorithmException e) {
120 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
121 }
122 }
123
124 public static String sha1hex(Path path) {
125 return digest(SHA1, path, byteBufferCapacity);
126 }
127
128 public static String digest(String algorithm, Path path, long bufferSize) {
129 byte[] digest = digestRaw(algorithm, path, bufferSize);
130 return encodeHexString(digest);
131 }
132
133 public static byte[] digestRaw(String algorithm, Path file, long bufferSize) {
134 long begin = System.currentTimeMillis();
135 try {
136 MessageDigest md = MessageDigest.getInstance(algorithm);
137 FileChannel fc = FileChannel.open(file);
138 long fileSize = Files.size(file);
139 if (fileSize <= bufferSize) {
140 ByteBuffer bb = fc.map(MapMode.READ_ONLY, 0, fileSize);
141 md.update(bb);
142 } else {
143 long lastCycle = (fileSize / bufferSize) - 1;
144 long position = 0;
145 for (int i = 0; i <= lastCycle; i++) {
146 ByteBuffer bb;
147 if (i != lastCycle) {
148 bb = fc.map(MapMode.READ_ONLY, position, bufferSize);
149 position = position + bufferSize;
150 } else {
151 bb = fc.map(MapMode.READ_ONLY, position, fileSize - position);
152 position = fileSize;
153 }
154 md.update(bb);
155 }
156 }
157 long end = System.currentTimeMillis();
158 if (debug)
159 System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
160 return md.digest();
161 } catch (Exception e) {
162 throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e);
163 }
164 }
165
166 public static void main(String[] args) {
167 File file;
168 if (args.length > 0)
169 file = new File(args[0]);
170 else {
171 System.err.println("Usage: <file> [<algorithm>]" + " (see http://java.sun.com/j2se/1.5.0/"
172 + "docs/guide/security/CryptoSpec.html#AppA)");
173 return;
174 }
175
176 if (args.length > 1) {
177 String algorithm = args[1];
178 System.out.println(digest(algorithm, file));
179 } else {
180 String algorithm = "MD5";
181 System.out.println(algorithm + ": " + digest(algorithm, file));
182 algorithm = "SHA";
183 System.out.println(algorithm + ": " + digest(algorithm, file));
184 System.out.println(algorithm + ": " + sha1hex(file.toPath()));
185 algorithm = "SHA-256";
186 System.out.println(algorithm + ": " + digest(algorithm, file));
187 algorithm = "SHA-512";
188 System.out.println(algorithm + ": " + digest(algorithm, file));
189 }
190 }
191
192 final private static char[] hexArray = "0123456789abcdef".toCharArray();
193
194 /**
195 * From
196 * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
197 * -a-hex-string-in-java
198 */
199 public static String encodeHexString(byte[] bytes) {
200 char[] hexChars = new char[bytes.length * 2];
201 for (int j = 0; j < bytes.length; j++) {
202 int v = bytes[j] & 0xFF;
203 hexChars[j * 2] = hexArray[v >>> 4];
204 hexChars[j * 2 + 1] = hexArray[v & 0x0F];
205 }
206 return new String(hexChars);
207 }
208
209 }