ict*_*her 5 java encryption blowfish
我正在使用一些使用Blowfish加密文本文件内容的java代码.当我将加密文件转换回来(即解密它)时,字符串从末尾开始缺少一个字符.有什么想法吗?我是Java的新手,并且在没有运气的情况下花了好几个小时.
war_and_peace.txt文件只包含字符串"This is some text".decrypted.txt包含"这是一些tex"(最后没有t).这是java代码:
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
private static byte[] getBytes(String toGet)
{
try
{
byte[] retVal = new byte[toGet.length()];
for (int i = 0; i < toGet.length(); i++)
{
char anychar = toGet.charAt(i);
retVal[i] = (byte)anychar;
}
return retVal;
}catch(Exception e)
{
String errorMsg = "ERROR: getBytes :" + e;
return null;
}
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
String iv = "12345678";
byte[] IVBytes = getBytes(iv);
IvParameterSpec IV = new IvParameterSpec(IVBytes);
byte[] KeyData = key.getBytes();
SecretKeySpec blowKey = new SecretKeySpec(KeyData, "Blowfish");
//Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
Cipher cipher = Cipher.getInstance("Blowfish/CBC/NoPadding");
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, blowKey, IV);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, blowKey, IV);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[4096];
//byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
public static void main(String[] args) {
//Encrypt the reports
try {
String key = "squirrel123";
FileInputStream fis = new FileInputStream("war_and_peace.txt");
FileOutputStream fos = new FileOutputStream("encrypted.txt");
encrypt(key, fis, fos);
FileInputStream fis2 = new FileInputStream("encrypted.txt");
FileOutputStream fos2 = new FileOutputStream("decrypted.txt");
decrypt(key, fis2, fos2);
} catch (Throwable e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
`
这里有一些不太理想的事情.
但我们首先要解决你的问题.输入的最后部分以某种方式丢失的原因是您指定的填充:无!如果不指定填充,则Cipher只能在全长块上运行(Blowfish为8个字节).超过一个块长的超额输入将被静默丢弃,并且您的文本丢失了.详细说明:"这是一些文本"长度为17个字节,因此将解密两个完整的块,最后的第17个字节"t"将被丢弃.
始终使用填充与对称分组密码组合,PKCS5Padding很好.
接下来,在使用时Cipher,您不需要实现自己的getBytes()- String#getBytes已经为您完成了这项工作.确保在获取字节时使用相同的字符编码,并在String稍后重建字节时,它是常见的错误来源.
您应该查看JCE文档,它们将帮助您避免一些常见错误.
例如,直接使用String键是对称密码术的禁忌,它们不包含足够的熵,这样可以更容易地强制使用这样的密钥.JCE为您提供KeyGenerator课程,除非您确切知道自己在做什么,否则应始终使用它.它为您生成一个适当大小的安全随机密钥,但此外,这是人们往往会忘记的东西,它还将确保它不会创建一个弱密钥.例如,在实际使用中应该避免使用已知的Blowfish弱键.
最后,在进行CBC加密时,不应使用确定性IV.最近有一些攻击可以利用它,导致消息完全恢复,这显然不是很酷.应始终随机选择IV(使用a SecureRandom)以使其不可预测.Cipher默认情况下为您执行此操作,您可以简单地获取加密后使用的IV Cipher#getIV.
另一方面,与安全性相关性较低:您应该关闭finally块中的流以确保它们不惜一切代价关闭 - 否则,如果出现异常,您将留下一个打开的文件句柄.
这是您的代码的更新版本,它考虑了所有这些方面(必须使用字符串而不是文件main,但您可以简单地用您在那里替换它):
private static final String ALGORITHM = "Blowfish/CBC/PKCS5Padding";
/* now returns the IV that was used */
private static byte[] encrypt(SecretKey key,
InputStream is,
OutputStream os) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
return cipher.getIV();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static void decrypt(SecretKey key,
byte[] iv,
InputStream is,
OutputStream os)
{
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static void doCopy(InputStream is, OutputStream os)
throws IOException {
try {
byte[] bytes = new byte[4096];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
} finally {
is.close();
os.close();
}
}
public static void main(String[] args) {
try {
String plain = "I am very secret. Help!";
KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
SecretKey key = keyGen.generateKey();
byte[] iv;
InputStream in = new ByteArrayInputStream(plain.getBytes("UTF-8"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
iv = encrypt(key, in, out);
in = new ByteArrayInputStream(out.toByteArray());
out = new ByteArrayOutputStream();
decrypt(key, iv, in, out);
String result = new String(out.toByteArray(), "UTF-8");
System.out.println(result);
System.out.println(plain.equals(result)); // => true
} catch (Exception e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6671 次 |
| 最近记录: |