gpt4 book ai didi

java - 伽罗瓦/计数器模式 (GCM/NoPadding) 未使用

转载 作者:行者123 更新时间:2023-11-30 10:01:03 28 4
gpt4 key购买 nike

我已经实现了 AES/CBC/PKCS5Padding 并想在 Java 1.8 中继续使用 AES/GCM/NoPadding 但一直收到 javax. crypto.AEADBadTagException:标签不匹配!

AES/CBC/PKCS5Padding 的当前实现非常好,在最近的 SonarQube 扫描中,我发现 AES/CBC/PKCS5Padding 不安全并且建议继续使用 AES/GCM/NoPadding

加密/解密算法将用于 REST API 调用,其中接收到的请求主体将被加密,应用程序将解密主体。

REST API 将由其他应用程序使用,并将拥有自己唯一的 secret 和加盐值来加密和解密数据,在后端,应用程序将使用分配的 secret 和加盐值来解密或加密数据。

下面是我写的加解密代码:


public SecretKey generateSecretKey(String password, byte[] iv) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), iv, 65536, 128); // AES-128
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = secretKeyFactory.generateSecret(spec).getEncoded();
return new SecretKeySpec(key, "AES");
}

public String encryptWithGCM(String plaintext, String secret, String salt)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, ShortBufferException, InvalidKeySpecException {

byte[] secretBytes = secret.getBytes();
byte[] iv = salt.getBytes();
SecureRandom random = new SecureRandom();
random.nextBytes(iv);

SecretKey key = generateSecretKey(secret, iv);


Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);
cipher.update(plaintext.getBytes());

byte [] encryptedData = cipher.doFinal(plaintext.getBytes());

ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + encryptedData.length);
byteBuffer.putInt(iv.length);
byteBuffer.put(iv);
byteBuffer.put(encryptedData);

return Base64.encodeBase64URLSafeString(byteBuffer.array());
}

public String decryptWithGCM(String encryptedText, String secret, String salt) throws BadPaddingException, IllegalBlockSizeException,
NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeySpecException {

byte[] encryptedData = Base64.decodeBase64(encryptedText.getBytes());
// byte[] iv = salt.getBytes();

ByteBuffer byteBuffer = ByteBuffer.wrap(encryptedData);
int noonceSize = byteBuffer.getInt();

//Make sure that the file was encrypted properly
if(noonceSize < 12 || noonceSize >= 16) {
throw new IllegalArgumentException("Nonce size is incorrect. Make sure that the incoming data is an AES encrypted file.");
}
byte[] iv = new byte[noonceSize];
byteBuffer.get(iv);

SecretKey key = generateSecretKey(secret, iv);

//get the rest of encrypted data
byte[] cipherBytes = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherBytes);

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);

byte[] decryptedText = cipher.doFinal(encryptedText.getBytes());

return new String(decryptedText);
}

加密逻辑工作得很好并返回一个加密的 String,但是当发送返回的 String 进行解密应用程序抛出以下错误:

javax.crypto.AEADBadTagException: Tag mismatch!
at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:578)
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1032)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:969)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.qfix.utils.VASDecryptService.decryptWithGCM(VASDecryptService.java:103)
at com.qfix.controller.TestController.decrypt(TestController.java:47)
at com.qfix.controller.TestController$$FastClassBySpringCGLIB$$ce1df123.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.qfix.controller.TestController$$EnhancerBySpringCGLIB$$92c88aec.decrypt(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter.doFilter(ResourceUrlEncodingFilter.java:59)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

我试着弄清楚这个问题,我了解到如果 SecretKey 是从同一个实例引用的,在加密和解密方法中都不会抛出错误,但是,如果 SecretKey在encrypt和decrypt方法中分别实例化(这是要求,因为这两个方法在不同的类中,不能合并为一个)然后抛出上述错误。

如果上述情况是正确的,那么我相信 AES/GCM/NoPadding 将起作用,因为将从集成应用程序后端接收加密值。

此外,如果上述情况是正确的,AES/GCM/NoPadding 的替代方案比 AES/CBC/PKCS5PADDING 安全得多.

最佳答案

代码中有两个小错误导致观察到 AEADBadTagException(标记不匹配):

  • 除了 doFinal -调用update -调用在 encryptWithGCM 方法中执行。 update 调用必须被删除,或者结果必须与 doFinal 调用的结果连接(导致 double 明文解密)。否则,密文和标签通常不匹配(至少对于长度为 16 字节或更多的明文)。
  • doFinal 调用中使用 decryptWithGCM 方法 encryptedText.getBytes()。这必须替换为 cipherBytes。后者包含密文和标签,而 encryptedText 另外 包含有关 IV 的信息(因此与标签不匹配)。

通过这些更改,代码可以运行。这两个错误都与是否使用相同实例执行加密和解密无关,因此(关于你问题的最后一部分)可能还有其他(可能与环境相关的)问题我但是无法重现。

关于java - 伽罗瓦/计数器模式 (GCM/NoPadding) 未使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57668541/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com