]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/DigestUtils.java
Make OSGi boot more robust against badly formatted bundles.
[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 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";
36
37 private static Boolean debug = false;
38 // TODO: make it writable
39 private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB
40
41 public static byte[] sha1(byte[] bytes) {
42 try {
43 MessageDigest digest = MessageDigest.getInstance(SHA1);
44 digest.update(bytes);
45 byte[] checksum = digest.digest();
46 return checksum;
47 } catch (Exception e) {
48 throw new UtilsException("Cannot SHA1 digest", e);
49 }
50 }
51
52 public static String digest(String algorithm, byte[] bytes) {
53 try {
54 MessageDigest digest = MessageDigest.getInstance(algorithm);
55 digest.update(bytes);
56 byte[] checksum = digest.digest();
57 String res = encodeHexString(checksum);
58 return res;
59 } catch (Exception e) {
60 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
61 }
62 }
63
64 public static String digest(String algorithm, InputStream in) {
65 try {
66 MessageDigest digest = MessageDigest.getInstance(algorithm);
67 // ReadableByteChannel channel = Channels.newChannel(in);
68 // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity);
69 // while (channel.read(bb) > 0)
70 // digest.update(bb);
71 byte[] buffer = new byte[byteBufferCapacity];
72 int read = 0;
73 while ((read = in.read(buffer)) > 0) {
74 digest.update(buffer, 0, read);
75 }
76
77 byte[] checksum = digest.digest();
78 String res = encodeHexString(checksum);
79 return res;
80 } catch (Exception e) {
81 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
82 } finally {
83 StreamUtils.closeQuietly(in);
84 }
85 }
86
87 public static String digest(String algorithm, File file) {
88 FileInputStream fis = null;
89 FileChannel fc = null;
90 try {
91 fis = new FileInputStream(file);
92 fc = fis.getChannel();
93
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);
100 } finally {
101 StreamUtils.closeQuietly(fis);
102 if (fc.isOpen())
103 try {
104 fc.close();
105 } catch (IOException e) {
106 // silent
107 }
108 }
109 }
110
111 protected static String digest(String algorithm, ByteBuffer bb) {
112 long begin = System.currentTimeMillis();
113 try {
114 MessageDigest digest = MessageDigest.getInstance(algorithm);
115 digest.update(bb);
116 byte[] checksum = digest.digest();
117 String res = encodeHexString(checksum);
118 long end = System.currentTimeMillis();
119 if (debug)
120 System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
121 return res;
122 } catch (NoSuchAlgorithmException e) {
123 throw new UtilsException("Cannot digest with algorithm " + algorithm, e);
124 }
125 }
126
127 public static String sha1hex(Path path) {
128 return digest(SHA1, path, byteBufferCapacity);
129 }
130
131 public static String digest(String algorithm, Path path, long bufferSize) {
132 byte[] digest = digestRaw(algorithm, path, bufferSize);
133 return encodeHexString(digest);
134 }
135
136 public static byte[] digestRaw(String algorithm, Path file, long bufferSize) {
137 long begin = System.currentTimeMillis();
138 try {
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);
144 md.update(bb);
145 } else {
146 long lastCycle = (fileSize / bufferSize) - 1;
147 long position = 0;
148 for (int i = 0; i <= lastCycle; i++) {
149 ByteBuffer bb;
150 if (i != lastCycle) {
151 bb = fc.map(MapMode.READ_ONLY, position, bufferSize);
152 position = position + bufferSize;
153 } else {
154 bb = fc.map(MapMode.READ_ONLY, position, fileSize - position);
155 position = fileSize;
156 }
157 md.update(bb);
158 }
159 }
160 long end = System.currentTimeMillis();
161 if (debug)
162 System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
163 return md.digest();
164 } catch (Exception e) {
165 throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e);
166 }
167 }
168
169 public static void main(String[] args) {
170 File file;
171 if (args.length > 0)
172 file = new File(args[0]);
173 else {
174 System.err.println("Usage: <file> [<algorithm>]" + " (see http://java.sun.com/j2se/1.5.0/"
175 + "docs/guide/security/CryptoSpec.html#AppA)");
176 return;
177 }
178
179 if (args.length > 1) {
180 String algorithm = args[1];
181 System.out.println(digest(algorithm, file));
182 } else {
183 String algorithm = "MD5";
184 System.out.println(algorithm + ": " + digest(algorithm, file));
185 algorithm = "SHA";
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));
192 }
193 }
194
195 final private static char[] hexArray = "0123456789abcdef".toCharArray();
196
197 /**
198 * From
199 * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
200 * -a-hex-string-in-java
201 */
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];
208 }
209 return new String(hexChars);
210 }
211
212 }