繁体   English   中英

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

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

我正在寻找一种将long转换为String并以“隐藏” long值的方式转换的简单方法。

我希望避免为此功能在项目中添加另一个.jar。

它不必是难以破解的加密,只是让经验不足的人随意看。

加成:

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

谢谢

如果

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,因为它占用的空间更少,并且看起来相当“随机”。

如果您只是感到困惑,那么一些琐碎的事情

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

为了揭示每个字符,对与前一个混淆的输入值进行XOR(第一个字符之前具有一些任意值)

嗯……没有更多细节,很难为此找到解决方案。 您可以做很多不同的事情来实现自己的目标……我想。

您可以将其与随机数进行XOR运算并存储两个数字。 当您的算法公开使用时(例如,如果您想将其放在开源中),这显然将无法工作。

或者,您可以使用一些对称加密算法,例如Twofish或Serpent。

如果将数字存储在客户端系统上并由客户端应用程序评估,那么所有这些都将是徒劳的。 分发应用程序后,客户端便可以访问其存储的所有内容。 如果信息有价值,则在您的应用程序发布后不久即可使用解密程序。 如果这不值得,那又何必呢?

我喜欢使用Long.toString(value,36)。 这将在基数为36的情况下打印数字,该数字是紧凑的,尽管是秘密的(假设数字> = 10),可以使用Long.parseLong(text,36)进行解析

带有一次性填充 (OTP)的XOR提供了完美的保密性。 我使用OTP编写了一个加密整数的密码。 我只是为了适应您的要求而对其进行了修改。 它将加长的盐加密成一个长为24字符的十六进制字符串,

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

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

暂无
暂无

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

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