简体   繁体   English

Java中长到字符串(和返回)的简单对称加密

[英]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. 我正在寻找一种将long转换为String并以“隐藏” long值的方式转换的简单方法。

I'd prefer to avoid adding another .jar to the project for this feature. 我希望避免为此功能在项目中添加另一个.jar。

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. 我的目的是在用户不知道计数器值(类似于tinyURL的哈希值)的情况下,将一个计数器值(类型为long)作为跟踪参数附加到URL上,以便servlet在URL时知道计数器的值。被点击。

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. 因此,您可以通过将某些32位数字乘以X来“加密”,然后再通过乘以Y来“解密”。您所需要做的就是找到一些满足条件的非平凡X和Y。

For instance, (X, Y) = (3766475841, 1614427073), or (699185821, 3766459317). 例如,(X,Y)=(3766475841,1614427073)或(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. 一旦有了A * X,您就可以使用Base-64或十六进制或URL中的某些类似方案对其进行编码。 I'd suggest Base64 because it takes up less space and looks fairly "random". 我建议使用Base64,因为它占用的空间更少,并且看起来相当“随机”。

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 long->字符串->每个字符的char数组,与先前的输出值(第一个字符之前的任意值)进行XOR char数组->字符串

To reveal for each character, XOR with the previous obfuscated input value (with some arbitrary value for before the first character) 为了揭示每个字符,对与前一个混淆的输入值进行XOR(第一个字符之前具有一些任意值)

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. 您可以将其与随机数进行XOR运算并存储两个数字。 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. 或者,您可以使用一些对称加密算法,例如Twofish或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). 我喜欢使用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) 这将在基数为36的情况下打印数字,该数字是紧凑的,尽管是秘密的(假设数字> = 10),可以使用Long.parseLong(text,36)进行解析

XOR with an one-time pad (OTP) provides perfect secrecy. 带有一次性填充 (OTP)的XOR提供了完美的保密性。 I wrote a cipher using OTP to encrypt integers. 我使用OTP编写了一个加密整数的密码。 I just adapted it to long to meet your requirement. 我只是为了适应您的要求而对其进行了修改。 It encrypts a long into a 24 char hex string with salt prepended, 它将加长的盐加密成一个长为24字符的十六进制字符串,

-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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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