文件加密Java
我正在制作一个系统,其中包含一些数据,我希望它以XML格式获取这些数据,并将其保存为txt文件中的加密字符串,稍后当软件再次打开时,解密文件并正常读取。我已经有了将xml转换成字符串的所有代码,我已经有了保存它的代码,我只需要一些加密/解密代码的帮助 注意:我确实找到了一些要加密/解密的代码,但似乎无法将代码拆分为两种方法 以下是我的尝试:文件加密Java,java,security,encryption,Java,Security,Encryption,我正在制作一个系统,其中包含一些数据,我希望它以XML格式获取这些数据,并将其保存为txt文件中的加密字符串,稍后当软件再次打开时,解密文件并正常读取。我已经有了将xml转换成字符串的所有代码,我已经有了保存它的代码,我只需要一些加密/解密代码的帮助 注意:我确实找到了一些要加密/解密的代码,但似乎无法将代码拆分为两种方法 以下是我的尝试: public class AesEncrDec { public static String encrypt(String Data) {
public class AesEncrDec
{
public static String encrypt(String Data)
{
byte[] byteCipherText = null;
try {
String plainData=Data,cipherText,decryptedText;
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecureRandom rnd = new SecureRandom();
SecretKey secretKey = keyGen.generateKey();
IvParameterSpec iv;
iv = new IvParameterSpec(rnd.generateSeed(16));
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE,secretKey,iv);
byte[] byteDataToEncrypt = plainData.getBytes();
byteCipherText = aesCipher.doFinal(byteDataToEncrypt);
cipherText = new BASE64Encoder().encode(byteCipherText);
return new String(byteCipherText);
} catch (InvalidKeyException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
}
return new String(byteCipherText);
}
public static String dencrypt(String Data)
{
byte[] byteDecryptedText = null;
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
IvParameterSpec iv;
SecureRandom rnd = new SecureRandom();
iv = new IvParameterSpec(rnd.generateSeed(16));
Cipher aesCipher = Cipher.getInstance("AES");
SecretKey secretKey = keyGen.generateKey();
aesCipher.init(Cipher.ENCRYPT_MODE,secretKey,iv);
byteDecryptedText = aesCipher.doFinal(Data.getBytes());
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(AesEncrDec.class.getName()).log(Level.SEVERE, null, ex);
}
return new String(byteDecryptedText);
}
}
编辑:在对@Libin的响应中,以下是错误
Mar 24, 2014 6:27:42 PM PrefsReadAndWrite.AesEncrDec decrypt
SEVERE: null
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 PrefsReadAndWrite.AesEncrDec.decrypt(AesEncrDec.java:61)
at PrefsReadAndWrite.AesEncrDec.decryptedString(AesEncrDec.java:104)
at smarthouse.SmartHouse.main(SmartHouse.java:12)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:554)
at PrefsReadAndWrite.AesEncrDec.decryptedString(AesEncrDec.java:105)
at smarthouse.SmartHouse.main(SmartHouse.java:12)
Java Result: 1
您没有定义要使用的填充,因此使用了实现定义的填充。根据你的错误,这可能是你的情况。指定填充和操作模式,例如AES/CBC/PKCS5P添加。由于您现在将使用CBC,因此还需要一个初始化向量:
IvParameterSpec iv = new IvParameterSpec(rnd.generateSeed(16));
aesCipher.init(Cipher.ENCRYPT_MODE,secretKey,iv);
其中rnd是一个SecureRandom实例。以字符串形式返回数据也是一个坏主意,直接使用字节。当然,按照Libins的建议使用相同的密钥进行加密和解密。您只需生成一次密钥,然后使用它进行加密和解密。。使用此代码 AppSecurity类应用于生成新密钥和加密/解密 方法对字符串进行加密
private static byte[] encryptedByte(String s) {
return AppSecurity.encrypt(YourApplication.getSecretKey(),toBytes(s));
}
方法对字节进行解密
private static String decryptedString(byte[] blob) {
// here getSecretKey() should be the one used on encryption
byte[] decrypted = AppSecurity.decrypt(YourApplication.getSecretKey(),blob);
return toString(decrypted);
}
方法将字节转换为字符串
public static String toString(byte[] bytes) {
try {
String s = new String(bytes ,"UTF-8");
return s;
} catch (UnsupportedEncodingException e) {
return null;
}
}
方法将字符串转换为字节
public static byte[] toBytes(String s) {
try {
return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {return null;}
}
有关如何在应用程序中使用此功能的详细信息:
在应用程序/applet类上初始化initSecurity方法,并将返回键存储到变量中,并在运行时使用它
假设类名为YourApplication.java
//添加此方法以读取文件或生成一个新密钥
private void initSecurity() {
final String secretFile = "secure_file";
boolean keyExists = false;
//check if secret key exist in secure file
try {
FileInputStream inputStream = openFileInput(secretFile);
mSecretKey = new byte[16];
int result = inputStream.read(mSecretKey);
if(result >0) {
keyExists = true;
}
inputStream.close();
}
catch (FileNotFoundException e) {}
catch (IOException e){}
if(!keyExists) {
// generate a key
mSecretKey = AppSecurity.generateKey();
if(mSecretKey != null) {
// write in a secure file inside the app
try {
// MODE_PRIVATE will create the file (or replace a file of the same name)
// and make it private to the application.
FileOutputStream outputStream = openFileOutput(secretFile,Context.MODE_PRIVATE);
outputStream.write(mSecretKey);
outputStream.close();
}
catch (FileNotFoundException e){}
catch (IOException e) {}
}
}
}
你说不能拆分代码到底是什么意思?另外,看到空的捕捉块会让大多数开发人员感到毛骨悚然;永远不要这样做。甚至不是为了好玩。plainData.getBytes@fge im实际上试图加密字符串而不是实际的xml即使在这种情况下,指定字符集;此加密内容的收件人的JRE/OS组合不能使用与您的JRE/OS组合相同的字符集。如果您不知道选择哪一个,请选择StandardCharsets.UTF_8。@fge谢谢您的解释,我将更改为我无法使用rnd.generateSeed16这是什么函数?@erickson:您为什么将其更改为PKCS5?我知道它是有效的,但这只是因为它被解释为pkcs7填充。PKCS5用于8字节块大小,而AES使用16字节块。因此,我建议使用PKCS7填充。@Caio Petrelli:使用SecureRandom对象。忘记提到这一点了,因为它们在该字段中非常常见。PKCS7Padding不是JCA标准算法名称定义的标准名称,因此一些提供程序将引发NoSuchAlgorithmException。当应用于长度超过8字节的块时,将PKCS5Padding解释为PKCS 7填充的提供程序是常见的。@Drunix ive尝试实现该代码,但它不起作用,仍然返回相同的错误,我要更新这个问题,看看运行时没有错误,但在加密和解密方法中都返回null。查看我的更新答案。调用encryptedByte对字符串进行加密,并使用decryptedString对加密的字节进行解密。您能看到它引发了什么异常吗?异常似乎在decrypt中。你使用的是加密所用的同一个密钥吗?你能举个例子说明我应该如何调用这些方法,以及如何打印encrypt和dencrypt值吗?我不确定我调用的方法是否正确。。对不起,我有点不知道我在编程
// initialize it on your app startup
String mSecretKey = initSecurity()
// call this method when you encrypt /decrypt
public static byte[] getSecretKey() { return mSecretKey; }
private void initSecurity() {
final String secretFile = "secure_file";
boolean keyExists = false;
//check if secret key exist in secure file
try {
FileInputStream inputStream = openFileInput(secretFile);
mSecretKey = new byte[16];
int result = inputStream.read(mSecretKey);
if(result >0) {
keyExists = true;
}
inputStream.close();
}
catch (FileNotFoundException e) {}
catch (IOException e){}
if(!keyExists) {
// generate a key
mSecretKey = AppSecurity.generateKey();
if(mSecretKey != null) {
// write in a secure file inside the app
try {
// MODE_PRIVATE will create the file (or replace a file of the same name)
// and make it private to the application.
FileOutputStream outputStream = openFileOutput(secretFile,Context.MODE_PRIVATE);
outputStream.write(mSecretKey);
outputStream.close();
}
catch (FileNotFoundException e){}
catch (IOException e) {}
}
}
}