简体   繁体   中英

simple symmetric encryption of long to String (and back) in java

I'm looking for a simple way to translate long to String and back in a way that will "hide" the long value.

I'd prefer to avoid adding another .jar to the project for this feature.

It does not have to be a hard-to-crack encryption, just to look random to the inexperienced eye.

Addition:

My purpose here is to attach a counter value (of type long) to URLs as a tracking parameter without the users aware of the counter's value (sort of like tinyURL's hash), so that the servlet will know the value of the counter when the URL is clicked.

Thanks

If

X * Y = 1 (mod 2^32)

then

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

So, you can "encrypt" some 32-bit number by multiplying it by X, and then later "decrypt" by multiplying by Y. All you need is to find some non-trivial X and Y that satisfy the condition.

For instance, (X, Y) = (3766475841, 1614427073), or (699185821, 3766459317). I just found these with a simple brute force program.

Once you have A*X you can encode it using Base-64 or hexadecimal or some similar scheme in the URL. I'd suggest Base64 because it takes up less space and looks fairly "random".

If you're just obfuscating, something trivial like

long -> string -> char array for each character, XOR with the previous output value (with some arbitrary value for before the first character) char array -> string

To reveal for each character, XOR with the previous obfuscated input value (with some arbitrary value for before the first character)

Uhm… without further details it's hard to come up with a solution on this. You can do lots of different things to accomplish your goal… I guess.

You could XOR it with a random number and store both numbers. This obviously won't work when your algorithm is out in the open (eg if you want to put it in open source).

Or you could use some symmetric encryption algorithm, eg Twofish or Serpent.

All of this is rather futile if the number is stored on the client system and evaluated by a client application. As soon as you hand out your application clients can access everything it stores. If the information is worth it, decryption programs will be available soon after your application is released. If it's not worth it, then why bother?

I like to use Long.toString(value, 36). This prints the number in base 36 which is compact, though cryptic (provided the number is >= 10) You can parse it with Long.parseLong(text, 36)

XOR with an one-time pad (OTP) provides perfect secrecy. I wrote a cipher using OTP to encrypt integers. I just adapted it to long to meet your requirement. It encrypts a long into a 24 char hex string with salt prepended,

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

Here is the code,

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);
        }
    }
}

为了以确定性方式加密短明文,您可能需要看看FFSEM

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM