Короткая, нечувствительная к регистру стратегия запутывания строк - PullRequest
3 голосов
/ 15 ноября 2011

Я ищу способ идентифицировать (т.е. кодировать и декодировать) набор строк Java с одним токеном.Идентификация не должна включать постоянство БД.До сих пор я изучал кодирование Base64 и шифрование DES, но оба они не оптимальны в отношении следующих требований:

  • Токен должен быть как можно короче
  • Токен должен быть нечувствительнымto case
  • Токен должен выдерживать циклический переход URLEncoder / Decoder (то есть будет использоваться в URL)

Является ли Base32 лучшим вариантом или есть лучшие варианты?Обратите внимание, что в первую очередь меня интересует сокращение и запутывание набора, шифрование / безопасность не важны.

Ответы [ 3 ]

2 голосов
/ 15 ноября 2011

Rot13 запутывает, но не укорачивает.Zip укорачивается (обычно), но не переносит обратный URL-адрес.Шифрование не укорачивается и может удлиняться.Хеширование сокращается, но является односторонним.У вас нет легкой проблемы.Base32 нечувствителен к регистру, но занимает больше места, чем Base64, а это не так.Я подозреваю, что вам придется отказаться или изменить ваши требования.Какие требования являются наиболее важными, а какие наименее важными?

2 голосов
/ 15 ноября 2011

Какова структура текста (т.е. набор строк)?Вы можете использовать свои знания об этом, чтобы закодировать его в сокращенной форме.Например, если у вас есть большое базовое десятичное число «1234567890», вы можете перевести его в 36-значное число, которое будет короче.

В противном случае похоже, что вы пытаетесь изобрести универсальный архиватор.

Если вам не важна длина, тогда да, обработка с помощью алфавитного кодировщика (такого как Base32) является единственным выбором.

Кроме того, если текст достаточно большой, возможно, вы могли бы сэкономить некоторое место с помощью gzippingэто.

1 голос
/ 18 ноября 2011

Я потратил некоторое время на это, и у меня есть для вас хорошее решение.

Кодируйте как base64, а затем как пользовательский base32, который использует 0-9a-v.По сути, вы размещаете биты 6 за раз (ваши символы равны 0-9a-zA-Z), а затем кодируете их 5 за раз.Это приводит к тому, что едва ли есть дополнительное пространство.Например, ABCXYZdefxyz123789 кодируется как i9crnsuj9ov1h8o4433i14

Вот реализация, которая работает, включая некоторый тестовый код, который доказывает, что он нечувствителен к регистру:

// Note: You can add 1 more char to this if you want to
static String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

private static String decodeToken(String encoded) {
    // Lay out the bits 5 at a time
    StringBuilder sb = new StringBuilder();
    for (byte b : encoded.toLowerCase().getBytes())
        sb.append(asBits(chars.indexOf(b), 5));

    sb.setLength(sb.length() - (sb.length() % 6));

    // Consume it 6 bits at a time
    int length = sb.length();
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < length; i += 6)
        result.append(chars.charAt(Integer.parseInt(sb.substring(i, i + 6), 2)));

    return result.toString();
}

private static String generateToken(String x) {
    StringBuilder sb = new StringBuilder();
    for (byte b : x.getBytes())
        sb.append(asBits(chars.indexOf(b), 6));

    // Round up to 5 bit multiple
    // Consume it 5 bits at a time
    int length = sb.length();
    sb.append("00000".substring(0, length % 5));
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < length; i += 5)
        result.append(chars.charAt(Integer.parseInt(sb.substring(i, i + 5), 2)));

    return result.toString();
}

private static String asBits(int index, int width) {
    String bits = "000000" + Integer.toBinaryString(index);
    return bits.substring(bits.length() - width);
}

public static void main(String[] args) {
    String input = "ABCXYZdefxyz123789";
    String token = generateToken(input);
    System.out.println(input + " ==> " + token);
    Assert.assertEquals("mixed", input, decodeToken(token));
    Assert.assertEquals("lower", input, decodeToken(token.toLowerCase()));
    Assert.assertEquals("upper", input, decodeToken(token.toUpperCase()));
    System.out.println("pass");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...