11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in compliance with the License. You may obtain a copy of the License at
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software distributed under the License
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * or implied. See the License for the specific language governing permissions and limitations under
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the License.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.hash;
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkState;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkPositionIndexes;
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Chars;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Ints;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Longs;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Shorts;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteBuffer;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteOrder;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.charset.Charset;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.security.MessageDigest;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.security.NoSuchAlgorithmException;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link HashFunction} adapter for {@link MessageDigest}s.
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author kevinb@google.com (Kevin Bourrillion)
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author andreou@google.com (Dimitris Andreou)
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertfinal class MessageDigestHashFunction extends AbstractStreamingHashFunction {
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final String algorithmName;
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final int bits;
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  MessageDigestHashFunction(String algorithmName) {
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.algorithmName = algorithmName;
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.bits = getMessageDigest(algorithmName).getDigestLength() * 8;
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public int bits() {
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return bits;
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static MessageDigest getMessageDigest(String algorithmName) {
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return MessageDigest.getInstance(algorithmName);
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (NoSuchAlgorithmException e) {
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new AssertionError(e);
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public Hasher newHasher() {
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new MessageDigestHasher(getMessageDigest(algorithmName));
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class MessageDigestHasher implements Hasher {
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final MessageDigest digest;
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final ByteBuffer scratch; // lazy convenience
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean done;
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private MessageDigestHasher(MessageDigest digest) {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.digest = digest;
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putByte(byte b) {
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(b);
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putBytes(byte[] bytes) {
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(bytes);
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putBytes(byte[] bytes, int off, int len) {
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkPositionIndexes(off, off + len, bytes.length);
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(bytes, off, len);
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putShort(short s) {
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putShort(s);
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, Shorts.BYTES);
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putInt(int i) {
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putInt(i);
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, Ints.BYTES);
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putLong(long l) {
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putLong(l);
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, Longs.BYTES);
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putFloat(float f) {
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putFloat(f);
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, 4);
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putDouble(double d) {
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putDouble(d);
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, 8);
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putBoolean(boolean b) {
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return putByte(b ? (byte) 1 : (byte) 0);
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putChar(char c) {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.putChar(c);
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      digest.update(scratch.array(), 0, Chars.BYTES);
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      scratch.clear();
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putString(CharSequence charSequence) {
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < charSequence.length(); i++) {
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        putChar(charSequence.charAt(i));
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public Hasher putString(CharSequence charSequence, Charset charset) {
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return putBytes(charSequence.toString().getBytes(charset.name()));
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (java.io.UnsupportedEncodingException impossible) {
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new AssertionError(impossible);
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotDone();
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      funnel.funnel(instance, this);
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private void checkNotDone() {
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkState(!done, "Cannot use Hasher after calling #hash() on it");
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public HashCode hash() {
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      done = true;
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return HashCodes.fromBytes(digest.digest());
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
174