我正在尝试创建一个要作为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)这里我漏掉了什么?
附言:我使用的是tink版本的1.3.0-rc1
发布于 2019-11-03 22:27:52
您正在初始化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));
}发布于 2019-11-23 19:12:09
我的答案取决于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);
}所有这些都与一个小样本main绑定在一起:
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
请记住,密钥需要安全地存储,因为任何有权访问密钥文件的人都可以解密您的message.the
https://stackoverflow.com/questions/58680609
复制相似问题