javax.crypto.BadPaddingException:给定最终块未正确填充
在com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:810)
但是只有当要加密的普通输入文本的长度(在C#侧)超过1393个字符时……但如果长度等于1393个字符,或者小于1393个字符,则它可以正常工作.
这是加密的C#代码:
private static string Encrypt(string textToEncrypt,string key) { try { RijndaelManaged rijndaelCipher = new RijndaelManaged(); rijndaelCipher.Mode = CipherMode.CBC; rijndaelCipher.Padding = PaddingMode.PKCS7; rijndaelCipher.KeySize = 0x80; // 256bit key rijndaelCipher.BlockSize = 0x80; byte[] pwdBytes = Encoding.UTF8.GetBytes(key); byte[] keyBytes = new byte[0x10]; int len = pwdBytes.Length; if (len > keyBytes.Length) { len = keyBytes.Length; } Array.copy(pwdBytes,keyBytes,len); rijndaelCipher.Key = keyBytes; rijndaelCipher.IV = keyBytes; ICryptoTransform transform = rijndaelCipher.CreateEncryptor(); byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt); return Convert.ToBase64String(transform.TransformFinalBlock(plainText,plainText.Length)); } catch (Exception ex) { throw ex; } }
以及用于解密的Java代码:
public static String Decrypt(String text,String key) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] keyBytes = new byte[16]; byte[] b = key.getBytes("UTF-8"); int len = b.length; if (len > keyBytes.length) { len = keyBytes.length; } System.arraycopy(b,len); SecretKeySpec keySpec = new SecretKeySpec(keyBytes,"AES"); IvParameterSpec ivSpec = new IvParameterSpec(keyBytes); cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec); BASE64Decoder decoder = new BASE64Decoder(); byte[] results = cipher.doFinal(decoder.decodeBuffer(text)); return new String(results,"UTF-8"); }
我已经尝试将BASE64Decoder从apache替换为Base64编解码器,但结果是一样的……
我会很感激任何建议或想法.谢谢.
解决方法
我重写了java解密端进行MAC验证.它假定MAC是使用HMACSHA1算法生成的,该算法使用与AES密码相同的密钥材料进行初始化(注意:这仅是一个示例,加密密钥和HMAC密钥在实际系统中应该是不同的)并且预先附加到密文.消息的前20个字节应该是MAC,然后是紧随其后的密文.
public static String Decrypt(String message,"AES"); IvParameterSpec ivSpec = new IvParameterSpec(keyBytes); byte[] messageBytes = DatatypeConverter.parseBase64Binary(message); byte[] macBytes = new byte[20]; byte[] ciphertext = new byte[messageBytes.length - 20]; System.arraycopy(messageBytes,macBytes,macBytes.length); System.arraycopy(messageBytes,20,ciphertext,ciphertext.length); Mac mac = Mac.getInstance("HMACSHA1"); mac.init(keySpec); verifyMac(mac.doFinal(ciphertext),macBytes); cipher.init(Cipher.DECRYPT_MODE,ivSpec); byte[] results = cipher.doFinal(ciphertext); return new String(results,"UTF-8"); } private static void verifyMac(byte[] mac1,byte[] mac2) throws Exception { MessageDigest sha = MessageDigest.getInstance("SHA1"); byte[] mac1_hash = sha.digest(mac1); sha.reset(); byte[] mac2_hash = sha.digest(mac2); if(!Arrays.equals(mac1_hash,mac2_hash)){ throw new RuntimeException("Invalid MAC"); } }
关于安全实践的一些注意事项.使用输入密码的UTF-8字节不会在您的密钥中提供足够的熵.如果您要使用密码作为加密密钥,则应使用密钥拉伸算法对其进行处理. PBKDF2是一个受欢迎的选择. AES密码的IV应该是随机生成的(使用加密安全的随机源),并使用密文以明文形式传输.用于初始化AES密码的密钥应该与用于MAC的密钥不同.您可以使用PBKDF2根据您提供的密码创建密钥的两倍,并将前半部分用于AES,将后半部分用于HMAC-SHA1.最后要注意的是,在验证MAC时,您应该直接验证MAC的散列而不是MAC(如上面的verifyMac方法中所示).验证MA直接暴露可能的定时攻击向量.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。