可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
回答1:
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".
回答2:
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)
回答3:
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 (e.g. if you want to put it in open source).
Or you could use some symmetric encryption algorithm, e.g. 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?
回答4:
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)
回答5:
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);
}
}
}
回答6:
For encrypting short plaintexts in a deterministic way, you might want to have a look at
FFSEM.