2015-05-07 4 views
0

Я хотел бы применить криптографический хэш к IP-номеру и иметь хэш в наборе символов «abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_».Как преобразовать массив байтов в строку под ограничительным набором символов?

Мои испытания до сих пор:

String ipWithSecret = secret + "123.123.123.123"; 
    byte[] ipBytes = ipWithSecret.getBytes(StandardCharsets.UTF_8); 
    MessageDigest md = MessageDigest.getInstance("MD5"); 
    byte[] mdBytes = md.digest(ipBytes); 
    System.out.println("MD5:  " + mdBytes); 
    System.out.println("US ASCII: " + new String(mdBytes, StandardCharsets.US_ASCII)); 
    System.out.println("Hex:  " + HexBin.encode(mdBytes)); 
    System.out.println("Base64: " + Base64.encodeBase64String(mdBytes));   
    System.out.print("Binary: "); 
    for (byte b : mdBytes) { 
     System.out.print(Integer.toBinaryString(b & 255 | 256).substring(1)); 
    } 

выходы:

MD5:  [[email protected] 
US ASCII: :???RN???z?}k^? 
Hex:  3A8BB1881E524EDFEFE67AFF7D6B5E9D 
Base64: OouxiB5STt/v5nr/fWtenQ== 
Binary: 00111010100010111011000110001000000111100101001001001110110111111110111111100110011110101111111101111101011010110101111010011101 

Кроме шестигранник, ничто не даже отдаленно приемлемым. Мой доступный алфавит намного больше, чем шестнадцатеричный, и, поскольку мне приходится иметь дело с лимитом длины в 16 символов, я хотел бы получить хэш-строку короче.

Любые предложения, как я могу это достичь?

Ответа на этот вопрос Я немного изменил ответ Джона, так что кредит ему принадлежит. Вот мой код, который также обрабатывает столкновения несколько:

String secret = "secret"; //config file, do not store in code 
    Set existingMdBase64Alt = new HashSet(Arrays.asList("OouxiB5STt_v5nr_", "ouxiB5STt_v5nr_f")); 
    String ipWithSecret = secret + "123.123.123.123"; 
    byte[] ipBytes = ipWithSecret.getBytes(StandardCharsets.UTF_8); 
    MessageDigest md = MessageDigest.getInstance("MD5"); 
    byte[] mdBytes = md.digest(ipBytes); 
    String mdBase64 = Base64.encodeBase64String(mdBytes); 
    String mdBase64Alt = mdBase64.replace("+","_").replace("/","_"); 
    System.out.println("Debug: " + mdBase64Alt.substring(0, 16)); 
    while (mdBase64Alt.length() > 16 && existingMdBase64Alt.contains(mdBase64Alt.substring(0, 16))){ 
     mdBase64Alt = mdBase64Alt.substring(1); 
     System.out.println("Debug: " + mdBase64Alt.substring(0, 16)); 
    } 
    System.out.println("Final: " + mdBase64Alt.substring(0, 16)); 
+2

Обратите внимание, что IP-адрес всего четыре байта (0-255x4), начните там вместо строки форма. –

ответ

4

В общем, не изобретать колесо: используйте base64. Это общее решение «короче, чем hex, но все еще пригодное для печати ASCII». Существуют различные доступные опции base64, в зависимости от того, какая версия Java вы используете и т. Д. Если в основной структуре нет ничего, мне нравится iharder.net public domain implementation.

Однако, это не действительно поможет вам здесь. Хэш MD5 составляет 16 байт, поэтому, если у вас нет 256 символов в вашем распоряжении (для представления каждого байта с одним символом), вы получите более 16 символов, просто из-за объема информации, re пытается представить.

Как отмечено в комментариях, адрес IPv4 составляет всего 4 байта. Честно говоря, хеширование, которое не собирается затушевывать его очень сильно, так как хэширование всего адресного пространства в высшей степени возможно ...

+1

Base64 имеет символы «+» и «=», в то время как мой набор символов имеет «_». Не идеальное совпадение, но я могу использовать замену строк на них и объединять их. Затем обрезайте строку с кодировкой base64. Это увеличит количество столкновений, но вероятность его, вероятно, еще приемлема. Для проблемы с небольшим доменом IP-адресов я просто добавлю секрет. – Claus

+0

@ Клаус: Да, ваш алфавит является очень болезненным, так как он имеет 63 символа. Трудно использовать 63 символа для произвольного кодирования октета, тогда как 64 (+ дополняющие) символы base64 допускают очень чистое кодирование 4char = 3 байта. Вы можете полностью исключить возможность столкновений, хотя путем кодирования (хотя вы хотите) 4 байта фактических данных ... неясно, что вы на самом деле пытаетесь достичь с этим, но используя MD5 по 4-байтовому значению в сущности, выглядит плохой идеей. –

+1

Я хочу использовать криптографические хэши IP-адресов, которые соответствуют моему набору символов. Первичное требование заключается в том, что исходные IP-адреса нельзя угадать. Вторичное для того, чтобы свести коллизии к минимуму. Конечно, он должен вписаться и в 16 символов. – Claus