Как генерировать строки, которые имеют один и тот же хэш-код в Java?
существующая система, написанная на Java, использует хэш-код строки в качестве стратегии маршрутизации для балансировки нагрузки.
Я не удается изменить систему но нужно генерировать строки, которые разделяют один и тот же хэш-код, чтобы проверить худшее состояние.
Я предоставляю эти строки из командной строки и надеюсь, что система направит все эти строки в одно и то же место назначения.
можно ли создать большое количество строк, которые разделяют тот же хэш-код?
чтобы прояснить этот вопрос:
String[] getStringsInSameHashCode(int number){
//return an array in length "number"
//Every element of the array share the same hashcode.
//The element should be different from each other
}
Примечания: любое значение хэш-кода приемлемо. Нет никаких ограничений на то, что строка. Но они должны отличаться друг от друга.
изменить: Переопределение метода класса String недопустимо, потому что я передаю эту строку из командной строки.
инструментирование также неприемлемо, потому что это окажет некоторое влияние на систему.
5 ответов
поскольку вы можете читать по-китайски вы можете посмотреть на мой пост http://www.hetaoblog.com/myblogs/post/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E9%87%8C%E9%9D%A2%E7%9A%84hashcode-string-hashcode.jhtml
см. метод теста, в основном, до тех пор, пока вы соответствуете, А1*31+В1 = А2*31 +В2, что означает, что (А1-А2)*31=В2-В1
public void testHash()
{
System.out.println("A:" + ((int)'A'));
System.out.println("B:" + ((int)'B'));
System.out.println("a:" + ((int)'a'));
System.out.println(hash("Aa".hashCode()));
System.out.println(hash("BB".hashCode()));
System.out.println(hash("Aa".hashCode()));
System.out.println(hash("BB".hashCode()));
System.out.println(hash("AaAa".hashCode()));
System.out.println(hash("BBBB".hashCode()));
System.out.println(hash("AaBB".hashCode()));
System.out.println(hash("BBAa".hashCode()));
}
вы получаете
A:65
B:66
a:97
2260
2260
2260
2260
2019172
2019172
2019172
2019172
edit: кто-то сказал, что это недостаточно просто. Я добавил ниже часть
@Test
public void testN() throws Exception {
List<String> l = HashCUtil.generateN(3);
for(int i = 0; i < l.size(); ++i){
System.out.println(l.get(i) + "---" + l.get(i).hashCode());
}
}
AaAaAa---1952508096
AaAaBB---1952508096
AaBBAa---1952508096
AaBBBB---1952508096
BBAaAa---1952508096
BBAaBB---1952508096
BBBBAa---1952508096
BBBBBB---1952508096
ниже приведен исходный код, он может быть неэффективным, но он работает:
public class HashCUtil {
private static String[] base = new String[] {"Aa", "BB"};
public static List<String> generateN(int n)
{
if(n <= 0)
{
return null;
}
List<String> list = generateOne(null);
for(int i = 1; i < n; ++i)
{
list = generateOne(list);
}
return list;
}
public static List<String> generateOne(List<String> strList)
{
if((null == strList) || (0 == strList.size()))
{
strList = new ArrayList<String>();
for(int i = 0; i < base.length; ++i)
{
strList.add(base[i]);
}
return strList;
}
List<String> result = new ArrayList<String>();
for(int i = 0; i < base.length; ++i)
{
for(String str: strList)
{
result.add(base[i] + str);
}
}
return result;
}
}
смотреть на строку.hashCode ()
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
Я думаю, что найти строку равного хэша из длинной строки слишком сложно, это легко, когда найти строку равного хэша короткой строки (2 или 3). Посмотрите на уравнение ниже. (извините, я не могу опубликовать изображение, чтобы вызвать меня новый участник)
обратите внимание, что "FB" и "Ea" имеют один и тот же хэш-код, а любые две строки, такие как s1+"FB"+s2 и s1+"Ea"+s2, будут иметь один и тот же хэш-код. Таким образом, простым решением является поиск любой подстроки 2-char существующей строки и замена подстроки 2-char на ту же хэш-код
Exmaple, у нас есть строка "helloworld" получить подстроку 2-char "he", хэш-код ("he") = 'h' * 31 + ' e ' = ('h' * 31 + 31) + ('e' - 31) = ('h'+1) * 31 + ' F ' = ' i ' + ' F ' = хэш-код ("iF") так что строки желание "iFlloworld" мы увеличили "h" на 1, мы можем увеличить на 2 или 3 и т. д. (Но будет неправильно, если он переполнит значение char)
приведенный ниже код работает хорошо с небольшим уровнем, это будет неправильно, если уровень Большой, сделать переполнение значения char, я исправлю это позже, если вы хотите (этот код меняет 2 первых символа, но я буду редактировать код до 2 последних символов, потому что 2 первых символа-calc с наибольшим значением)
public static String samehash(String s, int level) {
if (s.length() < 2)
return s;
String sub2 = s.substring(0, 2);
char c0 = sub2.charAt(0);
char c1 = sub2.charAt(1);
c0 = (char) (c0 + level);
c1 = (char) (c1 - 31 * level);
String newsub2 = new String(new char[] { c0, c1 });
String re = newsub2 + s.substring(2);
return re;
}
вы можете использовать java.ленг.Класс String, поэтому его метод hashCode () всегда будет возвращать одно и то же число.
Я полагаю, Javassist-самый простой способ сделать такое инструментирование.
короче:
- получить экземпляр java.ленг.инструмент.Инструментирование с помощью Java-агента (см. пакета java.ленг.документация по приборам дополнительные сведения)
- переопределить java.ленг.Класс String с использованием Аппаратура.redefineClasses(ClassDefinition[]) метод
код будет выглядеть так (грубо):
ClassPool classPool = new ClassPool(true);
CtClass stringClass = classPool.get("java.lang.String");
CtMethod hashCodeMethod = stringClass.getDeclaredMethod("hashCode", null);
hashCodeMethod.setBody("{return 0;}");
byte[] bytes = stringClass.toBytecode();
ClassDefinition[] classDefinitions = new ClassDefinition[] {new ClassDefinition(String.class, bytes);
instrumentation.redefineClasses(classDefinitions);// this instrumentation can be obtained via Java-agent
также не забывайте, что файл манифеста агента должен указывать Can-Redefine-Classes: true
чтобы иметь возможность использовать метод redefineClasses(ClassDefinition []).
мне было интересно, есть ли" универсальное " решение; например, некоторая постоянная строка XYZ
, таких, что
s.hashCode() == (s + XYZ).hashCode()
для любой строки s
. Поиск такой струны предполагает решение довольно сложного уравнения ... что было выше моих математических способностей. Но тут до меня дошло, что ... --4--> всегда true
, когда h
и ch
оба ноль!
основываясь на этом понимании, следующий метод должен создать другую строку с тем же хэш-код в качестве аргумента:
public String collider(String s) {
return "" + s;
}
если символы NUL для вас проблематичны, добавьтелюбой строка, хэш-код которой равен нулю, тоже будет работать ... хотя сталкивающиеся строки будут длиннее, чем если бы вы использовали ноль.
String s = "Some String"
for (int i = 0; i < SOME_VERY_BIG_NUMBER; ++i) {
String copy = new String(s);
// Do something with copy.
}
это будет работать для вас? Он просто создает много копий того же строкового литерала, который вы можете использовать в своем тестировании.