package com.constellio.data.utils.hashing; import java.io.*; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import com.constellio.data.conf.HashingEncoding; import com.constellio.data.io.EncodingService; import com.constellio.data.io.streamFactories.StreamFactory; import com.constellio.data.utils.Factory; import org.apache.commons.io.output.NullOutputStream; public class HashingService { private HashingEncoding hashingEncoding; private String algorithm; public HashingService(String algorithm, EncodingService encodingService, HashingEncoding hashingEncoding) { this.hashingEncoding = hashingEncoding; this.algorithm = algorithm; } public static HashingService forMD5(EncodingService encodingService, HashingEncoding hashingEncoding) { return new HashingService("MD5", encodingService, hashingEncoding); } public static HashingService forSHA1(EncodingService encodingService, HashingEncoding hashingEncoding) { return new HashingService("SHA1", encodingService, hashingEncoding); } public String getHashFromStream(StreamFactory<InputStream> streamFactory) throws HashingServiceException { InputStream inputStream = null; try { inputStream = streamFactory.create("getHashFromStream"); } catch (IOException e) { throw new HashingServiceException.CannotReadContent(e); } try { return getHashFromStream(inputStream); } finally { IOUtils.closeQuietly(inputStream); } } public String getHashFromStream(final InputStream stream) throws HashingServiceException { try { MessageDigest messageDigest = this.getDigest(); DigestInputStream dis = new DigestInputStream(stream, messageDigest); IOUtils.copy(dis, new NullOutputStream()); return this.encodeDigest(messageDigest.digest()); } catch (IOException e) { throw new HashingServiceException.CannotReadContent(e); } catch (RuntimeException e) { throw new HashingServiceException.CannotHashContent(e); } } public String getHashFromReader(final StreamFactory<Reader> readerFactory) throws HashingServiceException { Reader reader = null; try { reader = readerFactory.create("getHashFromReader"); } catch (IOException e) { throw new HashingServiceException.CannotReadContent(e); } try { return getHashFromReader(reader); } finally { IOUtils.closeQuietly(reader); } } public String getHashFromReader(final Reader reader) throws HashingServiceException { return getHashFromBytes(new Factory<byte[]>() { @Override public byte[] get() { try { return IOUtils.toByteArray(reader); } catch (IOException e) { throw new HashingServiceRuntimeException.CannotGetHashFromReader(e); } } }); } public String getHashFromFile(File file) throws HashingServiceException { try (FileInputStream fis = new FileInputStream(file)) { return getHashFromStream(fis); } catch (IOException e) { throw new HashingServiceRuntimeException.CannotGetHashFromStream(e); } } public String getHashFromBytes(final byte[] bytes) throws HashingServiceException { return getHashFromBytes(new Factory<byte[]>() { @Override public byte[] get() { return bytes; } }); } public String getHashFromBytes(final Factory<byte[]> bytesFactory) throws HashingServiceException { try { byte[] bytes; try { bytes = bytesFactory.get(); } catch (RuntimeException e) { throw new HashingServiceException.CannotReadContent(e); } return doHash(bytes); } catch (RuntimeException e) { throw new HashingServiceException.CannotHashContent(e); } } public String getHashFromString(String string) throws HashingServiceException { return getHashFromBytes(string.getBytes()); } String doHash(byte[] bytes) { MessageDigest messageDigest = getDigest(); byte[] digestBytes = messageDigest.digest(bytes); return encodeDigest(digestBytes); } private MessageDigest getDigest() { try { return MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { throw new HashingServiceRuntimeException.NoSuchAlgorithm(algorithm, e); } } String encodeDigest(byte[] digestBytes) { String encoded; if (hashingEncoding == HashingEncoding.BASE64_URL_ENCODED) { encoded = new EncodingService().encodeToBase64UrlEncoded(digestBytes); } else if (hashingEncoding == HashingEncoding.BASE32) { encoded = new EncodingService().encodeToBase32(digestBytes); } else { encoded = new EncodingService().encodeToBase64(digestBytes); } return encoded; } }