【问题标题】:Decryption erorr when using tink in Java在 Java 中使用 tink 时出现解密错误
【发布时间】:2019-11-03 13:28:21
【问题描述】:

我正在尝试创建要作为 REST API 响应发送的加密令牌。然后,最终用户可以在下一个请求期间向该 api 发送相同的令牌,我可以解析它并获取一些上下文信息(前一个)。

由于我是密码学的新手,我觉得最好选择Google tink,而不是自己编写加密/解密代码。但是我无法正确解密。

我正在做如下加密/解密:

public class CipherUtils {

    public static byte[] encrypt(byte[] plainText, 
                                 byte[] associatedData) throws GeneralSecurityException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.encrypt(plainText, associatedData);
    }

    public static byte[] decrypt(byte[] cipherText, 
                                 byte[] associatedData) throws GeneralSecurityException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.decrypt(cipherText, associatedData);
    }
}

这是我生成令牌的方式:

String associatedData = "somethingUnique";
String data = "tokenToBeEncrypted";

byte[] ciphered = CipherUtils.encrypt(data.getBytes(), associatedData.getBytes());
String finalToken = Base64.getEncoder().encodeToString(ciphered);

这个finalToken 作为响应被发回,并从下一个请求中检索。

这是我正在尝试解密的:

String associatedData = "somethingUnique"; // same one used for encrypting
String token = // retrieved from http request
byte[] decodedText = Base64.getDecoder().decode(token);
byte[] deciphered = CipherUtils.decrypt(decodedText, associatedData.getBytes());

这总是会导致以下异常:

java.security.GeneralSecurityException: decryption failed
    at com.google.crypto.tink.aead.AeadWrapper$WrappedAead.decrypt(AeadWrapper.java:82)
    at CipherUtils.decrypt(CipherUtils.java:22)

我在这里错过了什么?

P.S:我使用的是tink版本1.3.0-rc1

【问题讨论】:

  • generateNew 生成一个 new 密钥。由于您在encryptdecrypt 中都调用了generateNew,因此加密和解密使用不同的 密钥。因此解密失败。

标签: java encryption tink


【解决方案1】:

您正在初始化 AEAD 键集的两个单独实例。您需要初始化单个密钥集和 Aead 并引用相同的对象进行加密和解密

@Test
public void testEnc() throws GeneralSecurityException {
    AeadConfig.register();
    String associatedData = "somethingUnique";
    String data = "tokenToBeEncrypted";
    KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
    Aead aead = keysetHandle.getPrimitive(Aead.class);
    byte[] ciphered = aead.encrypt(data.getBytes(), associatedData.getBytes());
    byte[] deciphered = aead.decrypt(ciphered, associatedData.getBytes());
    assertEquals(data, new String(deciphered));

}

【讨论】:

【解决方案2】:

我的答案取决于 Topaco(11 月 3 日 14:27)的评论,并展示了一些如何解决问题的代码。由于即使要解密消息也会生成新密钥,但解密失败(用于加密的密钥与用于解密的密钥不同),因此您必须保存加密密钥并重新使用它进行解密。 在 Tink 中,这可以通过额外的一行代码来完成,这就是加密部分:

public static byte[] encrypt(byte[] plainText, byte[] associatedData) throws GeneralSecurityException, IOException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(new File("tinkkey.json"))); // new line
        return aead.encrypt(plainText, associatedData);
    }

现在是解密部分:

public static byte[] decrypt(byte[] cipherText, byte[] associatedData) throws GeneralSecurityException, IOException {
        // KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM); // deleted line
        KeysetHandle keysetHandle =  CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File("tinkkey.json"))); // new line
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.decrypt(cipherText, associatedData);
    }

全部用一个小样本主绑定在一起:

public static void main(String[] args) throws GeneralSecurityException, IOException {
        AeadConfig.register();
        byte[] encryptByte = encrypt("plain".getBytes("UTF-8"), "aad".getBytes("UTF-8"));
        byte[] decryptByte = decrypt(encryptByte, "aad".getBytes("UTF-8"));
        System.out.println("decrypted plaintext:" + new String(decryptByte, "UTF-8"));
    }

最后你得到解密的文本:

decrypted plaintext:plain

要保存密钥文件,您需要在类路径 (JSON Org) 上添加一个库,您可以在此处获取:https://mvnrepository.com/artifact/org.json/json

请记住,密钥需要安全存储,因为有权访问密钥文件的每个人都可以解密您的消息。

【讨论】:

    猜你喜欢
    • 2019-08-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    相关资源
    最近更新 更多