простое симметричное шифрование long для String (и обратно) в Java - PullRequest
1 голос
/ 10 сентября 2009

Я ищу простой способ перевода long в String и обратно таким образом, чтобы "скрыть" значение long.

Я бы предпочел не добавлять еще один .jar в проект для этой функции.

Это не должно быть трудно взломанное шифрование, просто чтобы выглядело случайным для неопытного глаза.

Дополнительно:

Моя цель здесь состоит в том, чтобы прикрепить значение счетчика (типа long) к URL-адресам в качестве параметра отслеживания, чтобы пользователи не знали о значении счетчика (вроде хэш-функции tinyURL), чтобы сервлет знал значение счетчика при нажатии на URL.

Спасибо

Ответы [ 6 ]

8 голосов
/ 10 сентября 2009

Если

X * Y = 1 (mod 2^32)

тогда

A * (X * Y) = A (mod 2^32)
(A * X) * Y = A (mod 2^32)

Таким образом, вы можете «зашифровать» некоторое 32-битное число, умножив его на X, а затем «расшифровать», умножив на Y. Все, что вам нужно, - это найти несколько нетривиальных X и Y, которые удовлетворяют условию.

Например, (X, Y) = (3766475841, 1614427073) или (699185821, 3766459317). Я нашел их с помощью простой программы грубой силы.

Если у вас есть A * X, вы можете кодировать его, используя Base-64 или шестнадцатеричный код, или какую-либо аналогичную схему в URL. Я бы предложил Base64, потому что он занимает меньше места и выглядит довольно «случайным».

2 голосов
/ 10 сентября 2009

Если вы просто запутываете, что-то тривиальное, как

long -> string -> char char для каждого символа XOR с предыдущим выходным значением (с некоторым произвольным значением перед первым символом) массив символов -> строка

Чтобы показать для каждого символа, XOR с предыдущим запутанным входным значением (с некоторым произвольным значением для перед первым символом)

1 голос
/ 08 ноября 2009

Мне нравится использовать Long.toString (значение, 36). Это печатает число в базе 36, которое является компактным, хотя и загадочным (при условии, что число> = 10). Вы можете проанализировать его с помощью Long.parseLong (text, 36)

1 голос
/ 10 сентября 2009

Хм ... без подробностей сложно найти решение по этому вопросу. Вы можете сделать много разных вещей для достижения своей цели ... Я думаю.

Вы можете сделать XOR случайным числом и сохранить оба числа. Это, очевидно, не сработает, когда ваш алгоритм открыт (например, если вы хотите поместить его в открытый код).

Или вы можете использовать некоторый алгоритм симметричного шифрования, например Двенадцать или Змей.

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

0 голосов
/ 08 ноября 2009

Для шифрования коротких открытых текстов детерминированным способом, возможно, вы захотите взглянуть на FFSEM .

0 голосов
/ 11 сентября 2009

XOR с одноразовым блокнотом (OTP) обеспечивает идеальную секретность. Я написал шифр с использованием OTP для шифрования целых чисел. Я просто приспособил его для того, чтобы соответствовать вашим требованиям. Он шифрует длинную строку в шестнадцатеричную шестнадцатеричную строку с добавлением соли,

-3675525778535888036 => 4fe555ca33021738a3797ab2
-6689673470125604264 => 76092fda5cd67e93b18b4f2f
 8956473951386520443 => 0fb25e533be315bdb6356a2a
 4899819575233977659 => 7cf17d74d6a2968370fbe149

Вот код,

public class IntegerCipher {
    // This is for salt so secure random is not needed
    private static Random PRNG = new Random();
    private String secret;

    public IntegerCipher(String secret) {
        if (secret.length() < 4)
            throw new IllegalArgumentException("Secret is too short");
        this.secret = secret;
    }

    public String encrypt(long value) {
        int salt = PRNG.nextInt();
        long otp = generatePad(salt);
        long cipher = value ^ otp;
        return String.format("%08x%016x", salt, cipher);
    }

    public long decrypt(String ciphertext) {
        if (ciphertext.length() != 24)
            throw new IllegalArgumentException("Invalid cipher text");
        try {
            int salt = (int) Long.parseLong(ciphertext.substring(0, 8), 16);
            long cipher = Long.parseLong(ciphertext.substring(8, 16), 16) << 32
                    | Long.parseLong(ciphertext.substring(16), 16);
            long otp = generatePad(salt);
            return cipher ^ otp;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid hex value: "
                    + e.getMessage());
        }
    }

    private long generatePad(int salt) {
        String saltString = Integer.toString(salt);
        String lpad = saltString + secret;
        String rpad = secret + saltString;
        return ((long) lpad.hashCode()) << 32 | (long) rpad.hashCode();
    }

    public static void main(String[] args) {
        IntegerCipher cipher = new IntegerCipher("Top Secret");
        Random rand = new Random();
        for (int i = 0; i < 100; i++) {
            Long n = rand.nextLong();
            String ciphertext = cipher.encrypt(n);
            Long m = cipher.decrypt(ciphertext);
            System.out.printf("%24d => %s\n", n,  ciphertext);
            assert(m == n);
        }
    }
}
...