我在找一个散列函数。就我的目的而言(在导入过程中标识更改的对象),它应该具有以下属性:
它不需要对创建冲突的恶意尝试具有安全性。
我能用什么算法?优先采用在Java中存在的免费实现的算法。
澄清
发布于 2014-11-18 18:00:10
哈希是一个明智的话题,很难根据您的问题推荐任何这样的散列。您可能需要在https://security.stackexchange.com/上问这个问题,以获得关于某些应用程序中hashs可用性的专家意见。
到目前为止,我所理解的是,大多数散列都是在核心中逐步实现的;另一方面,执行时间并不是那么容易预测。
我向您介绍两个Hasher实现,它们依赖于“在Java中存在的免费实现”。这两个实现的构造方式都可以在调用String之前任意拆分add(),并获得相同的结果,只要您不更改它们中字符的顺序:
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* Created for https://stackoverflow.com/q/26928529/1266906.
*/
public class Hashs {
public static class JavaHasher {
private int hashCode;
public JavaHasher() {
hashCode = 0;
}
public void add(String value) {
hashCode = 31 * hashCode + value.hashCode();
}
public int create() {
return hashCode;
}
}
public static class ShaHasher {
public static final Charset UTF_8 = Charset.forName("UTF-8");
private final MessageDigest messageDigest;
public ShaHasher() throws NoSuchAlgorithmException {
messageDigest = MessageDigest.getInstance("SHA-256");
}
public void add(String value) {
messageDigest.update(value.getBytes(UTF_8));
}
public byte[] create() {
return messageDigest.digest();
}
}
public static void main(String[] args) {
javaHash();
try {
shaHash();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace(); // TODO: implement catch
}
}
private static void javaHash() {
JavaHasher h = new JavaHasher();
h.add("somestring");
h.add("another part");
h.add("eveno more");
int hash = h.create();
System.out.println(hash);
}
private static void shaHash() throws NoSuchAlgorithmException {
ShaHasher h = new ShaHasher();
h.add("somestring");
h.add("another part");
h.add("eveno more");
byte[] hash = h.create();
System.out.println(Arrays.toString(hash));
System.out.println(new BigInteger(1, hash));
}
}在这里,"SHA-256“显然可以被其他常见的散列算法所取代;Java提供了相当多的散列算法。
现在,您调用了一个Long作为返回值,这意味着您正在寻找64位哈希。如果这真的是故意的,请看一下What is a good 64bit hash function in Java for textual strings?的答案。接受的答案是JavaHasher的一个细微的变体,因为String.hashCode()做的计算基本相同,但溢出边界较低:
public static class Java64Hasher {
private long hashCode;
public Java64Hasher() {
hashCode = 1125899906842597L;
}
public void add(CharSequence value) {
final int len = value.length();
for(int i = 0; i < len; i++) {
hashCode = 31*hashCode + value.charAt(i);
}
}
public long create() {
return hashCode;
}
}对你们的观点:
ShaHasher的那个属性是基于块的,而且我缺少源code.Still,我建议最多保留一个块、散列和一些内部状态。另外两个显然只存储对add()调用之间的部分散列。JavaHasher用于例如HashMap,并且似乎“无冲突”,足以将彼此相隔很远的类似密钥分发出去。至于更深层次的分析:做你自己的测试或者问你当地的安全工程师-对不起。我希望这给了一个好的起点,细节可能主要是基于意见的.
发布于 2014-11-19 16:05:48
不是作为一个答案,只是为了证明哈希碰撞比人类直觉假设的可能性大得多。
下面的小程序生成2^31个不同的字符串,并检查它们的散列是否发生碰撞。它通过保持每个可能的散列值的跟踪位(因此您需要>512 It堆来运行它)来实现这一点,并在遇到每个哈希值时将它们标记为"used“。它需要几分钟才能完成。
public class TestStringHashCollisions {
public static void main(String[] argv) {
long collisions = 0;
long testcount = 0;
StringBuilder b = new StringBuilder(64);
for (int i=0; i>=0; ++i) {
// construct distinct string
b.setLength(0);
b.append("www.");
b.append(Integer.toBinaryString(i));
b.append(".com");
// check for hash collision
String s = b.toString();
++testcount;
if (isColliding(s.hashCode()))
++collisions;
// progress printing
if ((i & 0xFFFFFF) == 0) {
System.out.println("Tested: " + testcount + ", Collisions: " + collisions);
}
}
System.out.println("Tested: " + testcount + ", Collisions: " + collisions);
System.out.println("Collision ratio: " + (collisions / (double) testcount));
}
// storage for 2^32 bits in 2^27 ints
static int[] bitSet = new int[1 << 27];
// test if hash code has appeared before, mark hash as "used"
static boolean isColliding(int hash) {
int index = hash >>> 5;
int bitMask = 1 << (hash & 31);
if ((bitSet[index] & bitMask) != 0)
return true;
bitSet[index] |= bitMask;
return false;
}
}您可以轻松地调整字符串生成部分,以测试不同的模式。
https://stackoverflow.com/questions/26928529
复制相似问题