我有一个安全课程项目,但有一个问题。
基本上,我正在尝试加密然后解密密码,但是我在解密时遇到此错误。
“使用填充密码解密时,输入长度必须是8的倍数”
我这样做正确吗?我在关注2012年的一篇文章。它仍然安全吗?
我也尝试替换算法,但似乎无济于事:
“ AES”,“ RSA / ECB / PKCS1Padding”,“ PBEWithHmacSHA256AndDESede” ..还有更多
我得到:
线程“主”中的异常java.security.NoSuchAlgorithmException:RSA / ECB / PKCS1Padding SecretKeyFactory不存在
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.util.Base64;
public class ProtectedConfigFile {
private static final char[] PASSWORD = "ytfchchchgcv".toCharArray();
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
};
public static void main(String[] args) throws Exception {
String originalPassword = "secret";
System.out.println("Original password: " + originalPassword);
String encryptedPassword = encrypt(originalPassword);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = decrypt(encryptedPassword);
System.out.println("Decrypted password: " + decryptedPassword);
}
private static String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return Base64.getEncoder().encodeToString(pbeCipher.doFinal(property.getBytes("UTF-8")));
}
private static String decrypt(String property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
byte[] decode = Base64.getDecoder().decode(pbeCipher.doFinal(property.getBytes("UTF-8")));
return decode.toString();
}
}
这将返回:
Original password: secret
Encrypted password: eG+qiRan1Cw=
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.PBES1Core.doFinal(PBES1Core.java:416)
at com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineDoFinal(PBEWithMD5AndDESCipher.java:316)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at ProtectedConfigFile.decrypt(ProtectedConfigFile.java:43)
at ProtectedConfigFile.main(ProtectedConfigFile.java:26)
最佳答案
您已将密文的base64编码放入encryptedPassword
中。您需要先对该字符串进行base64解码,然后再解密实际的密文。并且由于您的明文是UTF-8,因此您应该将解密后的明文解释为UTF-8。
return new String( pbeCipher.doFinal(Base64.getDecoder().decode(property)), "UTF-8");
而且没有DES是不安全的,并且事实上,根据攻击者的能力,DES已经处于暴力范围至少十年了。自1999年左右起就不推荐使用它,而首先支持“ triple-DES”(正式为TDEA),然后是AES,据我所知,它在2005年左右正式撤回。请参见https://en.wikipedia.org/wiki/Data_Encryption_Standard的第二段。 2012年编写的任何建议使用DES的建议均不胜任。
MD5被破坏是为了冲突,因此是为了签名(或至少是证书签名)。据我所知,这不会转化为对PBKDF的攻击,即使是用于PBEwithMD5andDES的较旧且已弃用的PBKDF1,也导致了许多人禁止使用MD5。
(更新)所有最新的Oracle Java中的内置提供程序都包括更好的Cipher
PBEwithSHA1andDESede
和可以从中构造任何(合理的)PBES2密码的SecretKeyFactory PBKDF2WithHmacSHA1
。 (前者实际上是PKCS#12 pbeWithSHAAnd3-keyTripleDES-CBC,正式名称为1.2.840.113549.1.12.1.3。)Java 8(仅)添加了一些很好的PBES2,这些PBES2已预先打包为Cipher PBEWithHmacSHA{1,224,256,384,512}AndAES_{128,256}
。任何一种都可以,尽管使用SHA1,您可能不得不向不知情的人解释,SHA1现在被认为有发生碰撞的风险,并且被禁止使用证书,但是对于KDF和PBE仍然可以,但是您可以通过仅使用SHA2来避免这种情况。 ,可能是最受欢迎的SHA256。另外,您肯定应该使用20次以上的迭代;甚至在1998年,RFC2898推荐的数量也至少为1000,而今天至少有成千上万,通常是一百万或更多。