使用 google tink 库解密密钥时出现标记不匹配错误
Tag Mismatch error when decrypting the key using google tink library
我是密码学的新手。我正在研究一个用于加密和解密字符串的 poc。当我解密加密的字符串时,它有时会起作用,但有时会抛出标签不匹配错误。我错过了什么吗?
这是我的代码:
EncryptionServiceImpl.java
public class EncryptionServiceImpl {
private static final Logger log = LoggerFactory.getLogger("EncryptionServiceImpl");
private final KeysetHandle keysetHandle;
private final Aead aead;
public EncryptionServiceImpl() throws GeneralSecurityException {
AeadConfig.register();
this.keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
aead = AeadFactory.getPrimitive(keysetHandle);
}
public String encrypt(String text) throws GeneralSecurityException {
log.info(String.format("Encrypting %s", text));
byte[] plainText = text.getBytes();
byte[] additionalData = "masterkey".getBytes();
byte[] cipherText = aead.encrypt(plainText,additionalData);
String output = new String(cipherText);
log.info(String.format("The encrypted text: %s", output));
return output;
}
public String decrypt(String text) throws GeneralSecurityException {
log.info(String.format("Decrypting %s", text));
byte[] cipherText = text.getBytes();
byte[] additionalData = "masterkey".getBytes();
byte[] decipheredData = aead.decrypt(cipherText,additionalData);
String output = new String(decipheredData);
log.info(String.format("The decrypted text: %s", output));
return output;
}
}
EncryptionServiceImplTest.java
public class EncryptionServiceImplTest {
@Test
public void encrypt() throws IOException, GeneralSecurityException {
EncryptionServiceImpl encryptionService = new EncryptionServiceImpl();
String encryptedText = encryptionService.encrypt("Hello World");
assertThat(encryptedText, Matchers.notNullValue());
}
@Test
public void decrypt() throws IOException, GeneralSecurityException {
EncryptionServiceImpl encryptionService = new EncryptionServiceImpl();
String encryptedText = encryptionService.encrypt("Hello World");
String decrypedText = encryptionService.decrypt(encryptedText);
assertThat(decrypedText, Matchers.is("Hello World"));
}
}
异常:
信息:密文前缀与密钥匹配,但无法解密:javax.crypto.AEADBadTagException:标签不匹配!
com.encryption.api.service.EncryptionServiceImplTest > 解密失败
java.security.GeneralSecurityException at EncryptionServiceImplTest.java:25
解密失败
java.security.GeneralSecurityException: 解密失败
在 com.google.crypto.tink.aead.AeadFactory$1.decrypt(AeadFactory.java:109)
在 com.encryption.api.service.EncryptionServiceImpl.decrypt(EncryptionServiceImpl.java:53)
在 com.encryption.api.service.EncryptionServiceImplTest.decrypt(EncryptionServiceImplTest.java:25)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:498)
在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(框架Method.java:50)
在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
在 org.junit.runners.model.FrameworkMethod.invokeExplosively(框架 Method.java:47)
在 org.junit.internal.runners.statements.InvokeMethod.evaluate(调用Method.java:17)
在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
在 org.junit.runners.ParentRunner.运行Children(ParentRunner.java:288)
在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
在 org.junit.runners.ParentRunner.运行(ParentRunner.java:363)
在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
在 org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:498)
在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
在 org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
在 org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
在 com.sun.proxy.$Proxy1.processTestClass(未知来源)
在 org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:108)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:498)
在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
在 org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
在 org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
在 org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
在 org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
在 org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
在 org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
在 java.lang.Thread.run(Thread.java:748)
1 个测试完成,1 个失败
如果加密消息的字节序列存储在字符串中,则必须使用适当的编码。适当意味着编码必须允许序列中的所有字节或字节组合。如果不是这种情况,字节序列中的值会自动更改,并且在存储期间不会被注意到。如果在解密期间从字符串重建字节数组,则原始字节数组和重建字节数组不同,解密失败。这很好解释here。
由于AES-GCM为每次加密生成一个新的初始化向量,因此每次加密的加密消息都是不同的,即使是相同的明文。
两者都会导致这样一个事实,即在您的示例中,加密有时有效,有时无效:只要字节序列与您使用的编码兼容,解密就有效,否则无效。
如果您想独立于编码,只需使用字节数组本身,即 encrypt
方法 returns 字节数组而不是字符串,类似地,而不是字节数组传递给 decrypt
方法的字符串。
我修改了代码,但我仍然发现有时同一请求的解密失败。
public class Utils {
private static final Logger log = LoggerFactory.getLogger(Utils.class);
private Aead aead;
private static Utils utils;
private Utils() {
try {
AeadConfig.register();
KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
aead = AeadFactory.getPrimitive(keysetHandle);
} catch (GeneralSecurityException e) {
log.error(String.format("Error occured: %s",e.getMessage())).log();
}
}
public static Utils getInstance() {
if(null == utils) {
utils = new Utils();
}
return utils;
}
public String encrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] plainText = text.getBytes("ISO-8859-1");
byte[] additionalData = null;
byte[] cipherText = aead.encrypt(plainText,additionalData);
String output = Base64.getEncoder().encodeToString(cipherText);
return output;
}
public String decrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] cipherText = Base64.getDecoder().decode(text);
byte[] additionalData = null;
byte[] decipheredData = aead.decrypt(cipherText,additionalData);
String output = new String(decipheredData,"ISO-8859-1");
return output;
}
}
当我在本地机器上 运行 时,我也没有在代码中遇到错误。但是当我部署在
云(google 云)我开始看到错误。
这是我的 Junit 代码:
public class UtilsTest {
private static final Utils cryptographicUtils = Utils.getInstance();
@Test
public void encrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello World");
assertThat(encryptedText, Matchers.notNullValue());
}
@Test
public void decrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello 123456");
String decrypedText = cryptographicUtils.decrypt(encryptedText);
assertThat(decrypedText, Matchers.is("Hello 123456"));
}
}
我是密码学的新手。我正在研究一个用于加密和解密字符串的 poc。当我解密加密的字符串时,它有时会起作用,但有时会抛出标签不匹配错误。我错过了什么吗?
这是我的代码:
EncryptionServiceImpl.java
public class EncryptionServiceImpl {
private static final Logger log = LoggerFactory.getLogger("EncryptionServiceImpl");
private final KeysetHandle keysetHandle;
private final Aead aead;
public EncryptionServiceImpl() throws GeneralSecurityException {
AeadConfig.register();
this.keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
aead = AeadFactory.getPrimitive(keysetHandle);
}
public String encrypt(String text) throws GeneralSecurityException {
log.info(String.format("Encrypting %s", text));
byte[] plainText = text.getBytes();
byte[] additionalData = "masterkey".getBytes();
byte[] cipherText = aead.encrypt(plainText,additionalData);
String output = new String(cipherText);
log.info(String.format("The encrypted text: %s", output));
return output;
}
public String decrypt(String text) throws GeneralSecurityException {
log.info(String.format("Decrypting %s", text));
byte[] cipherText = text.getBytes();
byte[] additionalData = "masterkey".getBytes();
byte[] decipheredData = aead.decrypt(cipherText,additionalData);
String output = new String(decipheredData);
log.info(String.format("The decrypted text: %s", output));
return output;
}
}
EncryptionServiceImplTest.java
public class EncryptionServiceImplTest {
@Test
public void encrypt() throws IOException, GeneralSecurityException {
EncryptionServiceImpl encryptionService = new EncryptionServiceImpl();
String encryptedText = encryptionService.encrypt("Hello World");
assertThat(encryptedText, Matchers.notNullValue());
}
@Test
public void decrypt() throws IOException, GeneralSecurityException {
EncryptionServiceImpl encryptionService = new EncryptionServiceImpl();
String encryptedText = encryptionService.encrypt("Hello World");
String decrypedText = encryptionService.decrypt(encryptedText);
assertThat(decrypedText, Matchers.is("Hello World"));
}
}
异常: 信息:密文前缀与密钥匹配,但无法解密:javax.crypto.AEADBadTagException:标签不匹配! com.encryption.api.service.EncryptionServiceImplTest > 解密失败
java.security.GeneralSecurityException at EncryptionServiceImplTest.java:25
解密失败 java.security.GeneralSecurityException: 解密失败 在 com.google.crypto.tink.aead.AeadFactory$1.decrypt(AeadFactory.java:109) 在 com.encryption.api.service.EncryptionServiceImpl.decrypt(EncryptionServiceImpl.java:53) 在 com.encryption.api.service.EncryptionServiceImplTest.decrypt(EncryptionServiceImplTest.java:25) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(框架Method.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(框架 Method.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(调用Method.java:17) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.运行Children(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.runners.ParentRunner.运行(ParentRunner.java:363) 在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114) 在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57) 在 org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66) 在 org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 在 org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32) 在 org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) 在 com.sun.proxy.$Proxy1.processTestClass(未知来源) 在 org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:108) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 在 org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 在 org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146) 在 org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128) 在 org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404) 在 org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63) 在 org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 在 org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55) 在 java.lang.Thread.run(Thread.java:748)
1 个测试完成,1 个失败
如果加密消息的字节序列存储在字符串中,则必须使用适当的编码。适当意味着编码必须允许序列中的所有字节或字节组合。如果不是这种情况,字节序列中的值会自动更改,并且在存储期间不会被注意到。如果在解密期间从字符串重建字节数组,则原始字节数组和重建字节数组不同,解密失败。这很好解释here。
由于AES-GCM为每次加密生成一个新的初始化向量,因此每次加密的加密消息都是不同的,即使是相同的明文。
两者都会导致这样一个事实,即在您的示例中,加密有时有效,有时无效:只要字节序列与您使用的编码兼容,解密就有效,否则无效。
如果您想独立于编码,只需使用字节数组本身,即 encrypt
方法 returns 字节数组而不是字符串,类似地,而不是字节数组传递给 decrypt
方法的字符串。
我修改了代码,但我仍然发现有时同一请求的解密失败。
public class Utils {
private static final Logger log = LoggerFactory.getLogger(Utils.class);
private Aead aead;
private static Utils utils;
private Utils() {
try {
AeadConfig.register();
KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
aead = AeadFactory.getPrimitive(keysetHandle);
} catch (GeneralSecurityException e) {
log.error(String.format("Error occured: %s",e.getMessage())).log();
}
}
public static Utils getInstance() {
if(null == utils) {
utils = new Utils();
}
return utils;
}
public String encrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] plainText = text.getBytes("ISO-8859-1");
byte[] additionalData = null;
byte[] cipherText = aead.encrypt(plainText,additionalData);
String output = Base64.getEncoder().encodeToString(cipherText);
return output;
}
public String decrypt(String text) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] cipherText = Base64.getDecoder().decode(text);
byte[] additionalData = null;
byte[] decipheredData = aead.decrypt(cipherText,additionalData);
String output = new String(decipheredData,"ISO-8859-1");
return output;
}
}
当我在本地机器上 运行 时,我也没有在代码中遇到错误。但是当我部署在 云(google 云)我开始看到错误。
这是我的 Junit 代码:
public class UtilsTest {
private static final Utils cryptographicUtils = Utils.getInstance();
@Test
public void encrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello World");
assertThat(encryptedText, Matchers.notNullValue());
}
@Test
public void decrypt() throws IOException, GeneralSecurityException {
String encryptedText = cryptographicUtils.encrypt("Hello 123456");
String decrypedText = cryptographicUtils.decrypt(encryptedText);
assertThat(decrypedText, Matchers.is("Hello 123456"));
}
}