使用Google Tink库解密密钥时出现标签不匹配错误

时间:2019-04-09 01:35:47

标签: java tink

我是密码学的新手。我正在研究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"));
    }
}

例外: INFO:密文前缀与密钥匹配,但无法解密: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(FrameworkMethod.java:50)     在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)     在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)     在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.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.runChildren(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.run(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个失败

3 个答案:

答案 0 :(得分:0)

如果加密消息的字节序列存储在字符串中,则必须使用适当的编码。适当意味着编码必须允许序列中的所有字节或字节组合。如果不是这种情况,则字节序列中的值会自动更改,并且在存储期间不会被注意。如果随后在解密过程中从字符串中重建了字节数组,则原始字节数组和重建的字节数组将不同,并且解密失败。 here对此进行了很好的解释。

由于AES-GCM为每种加密生成一个新的初始化向量,因此即使采用相同的明文,每种加密的加密消息也有所不同。

两者都导致一个事实,在您的示例中,加密有时有效,有时无效:只要字节序列与您使用的编码兼容,解密就起作用,否则无效。

如果要独立于编码,只需使用字节数组本身即可,即encrypt方法返回字节数组而不是字符串,类似地,返回字节数组而不是字符串传递给decrypt方法。

答案 1 :(得分:0)

我修改了代码,但仍然看到对于相同的请求解密有时会失败。

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

}

答案 2 :(得分:0)

当我在本地计算机上运行时,我也没有在代码中得到错误。但是当我部署在 云(谷歌云),我开始看到错误。

这是我的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"));
}

}