001/** 002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC 003 * and GZip files. (http://jwat.org/) 004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.jwat.common; 019 020import java.security.MessageDigest; 021import java.security.NoSuchAlgorithmException; 022import java.security.Provider; 023import java.util.Arrays; 024import java.util.Map; 025import java.util.TreeMap; 026import java.util.zip.CRC32; 027import java.util.zip.Checksum; 028 029/** 030 * This class represents a message digest including information about algorithm 031 * and encoding used. 032 * 033 * @author nicl 034 */ 035public class Digest { 036 037 static { 038 Provider[] providers = SecurityProviderTools.getSecurityProviders(); 039 if (!SecurityProviderTools.isProviderAvailable(providers, "BC")) { 040 SecurityProviderTools.loadBCProvider(); 041 } 042 } 043 044 /** Digest algorithm used. */ 045 public String algorithm; 046 047 /** Digest in bytes as returned by e.g. <code>MessageDigest</code>. */ 048 public byte[] digestBytes; 049 050 /** Digest string, encoded. */ 051 public String digestString; 052 053 /** Digest encoding used. (E.g. Base16, 32 or 64) */ 054 public String encoding; 055 056 /** Cache length of algorithm digest output. */ 057 protected static Map<String, Integer> digestAlgoLengthache = new TreeMap<String, Integer>(); 058 059 /** 060 * Returns the length of an algorithms digest output or -1 if it is an 061 * invalid digest algorithm. 062 * @param digestAlgorithm digest algorithm 063 * @return digest algorithm output length or -1 if invalid digest algorithm 064 */ 065 public static synchronized int digestAlgorithmLength(String digestAlgorithm) { 066 if (digestAlgorithm == null || digestAlgorithm.length() == 0) { 067 throw new IllegalArgumentException("'digestAlgorithm' is empty or null"); 068 } 069 Integer cachedLen = digestAlgoLengthache.get(digestAlgorithm); 070 if (cachedLen == null) { 071 try { 072 MessageDigest md = MessageDigest.getInstance(digestAlgorithm); 073 byte[] digest = md.digest(new byte[16]); 074 cachedLen = digest.length; 075 md.reset(); 076 } catch (NoSuchAlgorithmException e) { 077 } 078 if (cachedLen == null) { 079 cachedLen = -1; 080 } 081 digestAlgoLengthache.put(digestAlgorithm, cachedLen); 082 } 083 return cachedLen; 084 } 085 086 @Override 087 public boolean equals(Object obj) { 088 if (obj == null || !(obj instanceof Digest)) { 089 return false; 090 } 091 Digest digestObj = (Digest)obj; 092 if (!Arrays.equals(digestBytes, digestObj.digestBytes)) { 093 return false; 094 } 095 if (algorithm != null) { 096 if (!algorithm.equals(digestObj.algorithm)) { 097 return false; 098 } 099 } else if (digestObj.algorithm != null) { 100 return false; 101 } 102 if (digestString != null) { 103 if (!digestString.equals(digestObj.digestString)) { 104 return false; 105 } 106 } else if (digestObj.digestString != null) { 107 return false; 108 } 109 if (encoding != null) { 110 if (!encoding.equals(digestObj.encoding)) { 111 return false; 112 } 113 } else if (digestObj.encoding != null) { 114 return false; 115 } 116 return true; 117 } 118 119 @Override 120 public int hashCode() { 121 int hashCode = 0; 122 if (digestBytes != null) { 123 Checksum checksum = new CRC32(); 124 checksum.update(digestBytes, 0, digestBytes.length); 125 hashCode ^= checksum.getValue(); 126 } 127 if (algorithm != null) { 128 hashCode ^= algorithm.hashCode(); 129 } 130 if (digestString != null) { 131 hashCode ^= digestString.hashCode(); 132 } 133 if (encoding != null) { 134 hashCode ^= encoding.hashCode(); 135 } 136 return hashCode; 137 } 138 139}