gpt4 book ai didi

java - 给定最终 block 在 AES 解密时未正确填充

转载 作者:行者123 更新时间:2023-11-29 03:13:01 25 4
gpt4 key购买 nike

首先,我将说明我的主要目标是什么。我将在客户端使用 AES 加密一些内容,然后使用 RSA 公钥加密重要的 AES 规范,并将 AES 加密数据和 RSA 加密 AES 规范发送到服务器。因此,在服务器上,我将使用 RSA 私钥解密 AES key 规范,然后使用这些 AES 规范,我将解密 AES 加密数据。我已经通过测试加密和解密成功地使 RSA 部分工作。在实现 RSa 之前,我必须让这个 AES 艺术工作。

对于客户端,我使用的是 crypto-js

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
<script type="text/javascript" src="jquery-1.7.1.js"></script>
<script type="text/javascript">

$("#submit").click(function() {
var salt = CryptoJS.lib.WordArray.random(16);
var iv = CryptoJS.lib.WordArray.random(16);
var pass = CryptoJS.lib.WordArray.random(16);
var message = "Test Message for encryption";
var key128Bits = CryptoJS.PBKDF2(pass, salt, { keySize: 128 });
var key128Bits10Iterations = CryptoJS.PBKDF2(pass, salt, { keySize: 128, iterations: 10 });
var encrypted = CryptoJS.AES.encrypt(message, key128Bits10Iterations, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
var cipherData = encrypted.toString()+":"+salt.toString()+":"+iv.toString()+":"+pass.toString();
console.log(cipherData);

$.ajax({
url: 'encryption',
type: 'POST',
data: {
cipherData: cipherData
},
success: function(data) {
console.log(data);
},
failure: function(data) {

}
});
});

</script>

这是我在服务器端使用的代码

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String encryptedData = request.getParameter("cipherData");
String data[] = encryptedData.split(":");

String encrypted = data[0];
String salt = data[1];
String iv = data[2];
String password = data[3];

byte[] saltBytes = hexStringToByteArray(salt);
byte[] ivBytes = hexStringToByteArray(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
SecretKeySpec sKey = null;
try {
sKey = (SecretKeySpec) generateKeyFromPassword(password, saltBytes);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
try {
System.out.println( decrypt( encrypted , sKey ,ivParameterSpec));
} catch (Exception e) {
e.printStackTrace();
}
}

public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes) throws GeneralSecurityException {

KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 10, 128);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = keyFactory.generateSecret(keySpec);

return new SecretKeySpec(secretKey.getEncoded(), "AES");
}

public static byte[] hexStringToByteArray(String s) {

int len = s.length();
byte[] data = new byte[len / 2];

for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}

return data;

}

public static String decrypt(String encryptedData, SecretKeySpec sKey, IvParameterSpec ivParameterSpec) throws Exception {

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, sKey, ivParameterSpec);
byte[] decordedValue = Base64.decodeBase64(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);

return decryptedValue;
}

首先,我必须确保服务器收到的数据与我发送的数据相同。所以我通过 sysout 测试了它的加密、salt、iv 和密码。它收到了相同的数据。但是我在行中遇到了异常

byte[] decValue = c.doFinal(decordedValue);

javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2121)
at com.Encryption.decrypt(Encryption.java:95)
at com.Encryption.doPost(Encryption.java:60)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
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)

您可以看到,在 Javascript 端,它是 CryptoJS.pad.Pkcs7 ,在服务器端,它是 AES/CBC/PKCS5Padding ,我对此进行了一些搜索,发现两者是相同的。我不能将其更改为 CryptoJS.pad.Pkcs5 或 AES/CBC/PKCS7Padding,后者未针对 Crypto-js 库和 Java 内置库定义。

我也有以下想法。在 javascript 中,我使用随机盐并传递生成 128 位 key 。使用相同的 salt 和 pass,我通过定义适当的迭代计数和 key 大小在 Java 中生成相同的 key 。为什么我必须通过再次生成相同的 key 来延长 Java 中的过程?我可以简单地将 key (encrypted.key)、encrytedData(encrypted.toString()) 和 Iv (encrypted.iv) 发送到服务器并立即解密数据,而无需再次生成 key 。我对这个..?我也试过这个,我得到“无效的 AES key 长度异常”。为了维护安全,我将使用 RSA 公钥在客户端对 key 和 Iv 进行加密。使用非对称实现对称的原因之一是由于 RSA 的加密数据大小有限。但是如果我不能清除这个 BadPaddingException,我就不能实现它。

最佳答案

既然你想使用 RSA 并且已经实现了它,就没有必要使用密码派生。创建随 secret 钥和随机 iv:

var key = CryptoJS.lib.WordArray.random(16); // 128bit
var iv = CryptoJS.lib.WordArray.random(16); // 128bit
var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv }); // CBC/PKCS#7 is default

然后你发送iv.toString(Crypto.enc.Base64), encrypted.ciphertext.toString(Crypto.enc.Base64) 和“RSAencrypt(key)”到服务器,对base64编码的iv和密文进行解码,对RSA密文进行解密得到AES key ,将它们组合起来解密密文。


您最初的问题可能出在您使用的尺寸上。 CryptoJS 有一个内部表示,每个字由 4 个字节组成。这就是为什么您需要除以 32 以获得 128 位散列的原因:

var key128Bits = CryptoJS.PBKDF2(pass, salt, { keySize: 128/32 });

另一方面,WordArray 仅适用于字节,这就是为什么要除以 8:

var key = CryptoJS.lib.WordArray.random(128/8);

关于java - 给定最终 block 在 AES 解密时未正确填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28263491/

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