2023-03-13 17:00:47 +00:00
|
|
|
// Copyright 2023 Google LLC
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2022-09-18 00:51:14 +00:00
|
|
|
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
|
|
|
|
import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow;
|
|
|
|
import com.google.common.hash.HashCode;
|
|
|
|
import com.google.common.hash.Hasher;
|
|
|
|
import com.google.common.hash.HashFunction;
|
|
|
|
import com.google.common.hash.Hashing;
|
|
|
|
import java.lang.IllegalStateException;
|
|
|
|
|
|
|
|
public class HashingFuzzer {
|
|
|
|
|
|
|
|
public static class HashInputData {
|
|
|
|
|
|
|
|
public HashInputData(FuzzedDataProvider fuzzedDataProvider) {
|
|
|
|
m_bool = fuzzedDataProvider.consumeBoolean();
|
|
|
|
m_bytes = fuzzedDataProvider.consumeBytes(2);
|
|
|
|
m_char = fuzzedDataProvider.consumeChar();
|
|
|
|
m_double = fuzzedDataProvider.consumeDouble();
|
|
|
|
m_float = fuzzedDataProvider.consumeFloat();
|
|
|
|
m_int = fuzzedDataProvider.consumeInt();
|
|
|
|
m_long = fuzzedDataProvider.consumeLong();
|
|
|
|
m_short = fuzzedDataProvider.consumeShort();
|
|
|
|
m_string = fuzzedDataProvider.consumeRemainingAsString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getBoolean() {
|
|
|
|
return m_bool;
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte getByte() {
|
|
|
|
return (m_bytes.length > 0) ? m_bytes[0] : (byte)m_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte[] getBytes() {
|
|
|
|
return m_bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
public char getChar() {
|
|
|
|
return m_char;
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getDouble() {
|
|
|
|
return m_double;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getFloat() {
|
|
|
|
return m_float;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getInt() {
|
|
|
|
return m_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getLong() {
|
|
|
|
return m_long;
|
|
|
|
}
|
|
|
|
|
|
|
|
public short getShort() {
|
|
|
|
return m_short;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getString() {
|
|
|
|
return m_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean m_bool;
|
|
|
|
private byte m_bytes[];
|
|
|
|
private char m_char;
|
|
|
|
private double m_double;
|
|
|
|
private float m_float;
|
|
|
|
private int m_int;
|
|
|
|
private long m_long;
|
|
|
|
private short m_short;
|
|
|
|
private String m_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void testHashCode(HashCode hc) {
|
|
|
|
try {
|
|
|
|
hc.bits();
|
|
|
|
|
|
|
|
try {
|
|
|
|
int i = hc.asInt();
|
|
|
|
HashCode.fromInt(i);
|
|
|
|
} catch (IllegalStateException ise) {
|
|
|
|
/* documented, ignore */
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
long l = hc.asLong();
|
|
|
|
HashCode.fromLong(l);
|
|
|
|
} catch (IllegalStateException ise) {
|
|
|
|
/* documented, ignore */
|
|
|
|
}
|
|
|
|
|
|
|
|
hc.padToLong();
|
|
|
|
byte[] bytes = hc.asBytes();
|
|
|
|
hc.writeBytesTo(bytes,0,bytes.length);
|
|
|
|
HashCode.fromBytes(bytes);
|
|
|
|
|
|
|
|
String s = hc.toString();
|
|
|
|
HashCode.fromString(s);
|
|
|
|
|
|
|
|
hc.hashCode();
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
/* ignore */
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new FuzzerSecurityIssueLow("Undocumented Exception");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void testHash(HashFunction hash, HashInputData hashInputData) {
|
|
|
|
HashCode hc = null;
|
|
|
|
try {
|
|
|
|
Hasher h = hash.newHasher();
|
|
|
|
h.putBoolean(hashInputData.getBoolean());
|
|
|
|
h.putByte(hashInputData.getByte());
|
|
|
|
h.putBytes(hashInputData.getBytes());
|
|
|
|
h.putChar(hashInputData.getChar());
|
|
|
|
h.putDouble(hashInputData.getDouble());
|
|
|
|
h.putFloat(hashInputData.getFloat());
|
|
|
|
h.putInt(hashInputData.getInt());
|
|
|
|
h.putLong(hashInputData.getLong());
|
|
|
|
h.putShort(hashInputData.getShort());
|
|
|
|
h.putUnencodedChars(hashInputData.getString());
|
|
|
|
hc = h.hash();
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
/* ignore */
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new FuzzerSecurityIssueLow("Undocumented Exception");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hc != null) {
|
|
|
|
testHashCode(hc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fromString documents it accepts only well-formated input,
|
|
|
|
* but doesn't document what it does when ill-formated input
|
|
|
|
* is provided. Feed it some fuzz data and find out.
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
HashCode.fromString(hashInputData.getString());
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
/* ignore */
|
|
|
|
} catch(Exception e) {
|
|
|
|
e.printStackTrace(System.out);
|
|
|
|
throw new FuzzerSecurityIssueLow("Undocumented Exception");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) {
|
2023-03-13 17:00:47 +00:00
|
|
|
// Choose realistic and valid minimumBits value; this is normally not controlled by the user
|
|
|
|
int minimumBits = fuzzedDataProvider.consumeInt(1, 8192);
|
2022-09-18 00:51:14 +00:00
|
|
|
int seed = fuzzedDataProvider.consumeInt();
|
|
|
|
int k0 = fuzzedDataProvider.consumeInt();
|
|
|
|
int k1 = fuzzedDataProvider.consumeInt();
|
|
|
|
|
|
|
|
HashInputData hashInputData = new HashInputData(fuzzedDataProvider);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* testHash handles exceptions itself, so this try-block
|
|
|
|
* only catches exceptions thrown by Hashing's "factory"
|
|
|
|
* functions, none of which is documented to throw
|
|
|
|
* exceptions.
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
testHash(Hashing.adler32(), hashInputData);
|
|
|
|
testHash(Hashing.crc32(), hashInputData);
|
|
|
|
testHash(Hashing.crc32c(), hashInputData);
|
|
|
|
testHash(Hashing.farmHashFingerprint64(), hashInputData);
|
|
|
|
testHash(Hashing.goodFastHash(minimumBits), hashInputData);
|
|
|
|
testHash(Hashing.murmur3_128(), hashInputData);
|
|
|
|
testHash(Hashing.murmur3_128(seed), hashInputData);
|
|
|
|
testHash(Hashing.murmur3_32(), hashInputData);
|
|
|
|
testHash(Hashing.murmur3_32(seed), hashInputData);
|
|
|
|
testHash(Hashing.md5(), hashInputData);
|
|
|
|
testHash(Hashing.sha1(), hashInputData);
|
|
|
|
testHash(Hashing.sha256(), hashInputData);
|
|
|
|
testHash(Hashing.sha384(), hashInputData);
|
|
|
|
testHash(Hashing.sha512(), hashInputData);
|
|
|
|
testHash(Hashing.sipHash24(), hashInputData);
|
|
|
|
testHash(Hashing.sipHash24(k0, k1), hashInputData);
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
/* ignore */
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace(System.out);
|
|
|
|
throw new FuzzerSecurityIssueLow("Undocumented Exception");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|