为什么我的 AES 加密会抛出 InvalidKeyException? [英] Why does my AES encryption throws an InvalidKeyException?
问题描述
我目前正在研究使用密钥加密/解密特定文件的函数.我写了三个类,一个生成密钥,一个用密钥加密文件,一个解密.
生成密钥并加密文件工作正常,但是当我尝试解密文件时,在以下行抛出异常:c.init(Cipher.DECRYPT_MODE, keySpec);
:><块引用>
java.security.InvalidKeyException:缺少参数
我认为我在将密钥流式传输到我的 byte[]
时做错了什么,或者在解密文件时出现了一些错误.
三个类的快速解释: KeyHandler 创建一个 AES 密钥并将其存储在硬盘上.出于测试目的,密钥/明文/加密/解密文件的名称目前是硬编码的.
EncryptionHandler
将磁盘上的 .txt 文件转换为字节,使用密钥加密文件,然后使用 CipherOutputStream
将加密的字节写入磁盘.>
DecryptionHandler
当然与 EncryptionHandler
相反.
代码如下:
公共类 KeyHandler {Scanner scan = new Scanner(System.in);公共密钥处理程序(){尝试 {开始菜单();} 捕获(异常 e){System.out.println("fel någonstanns :)");}}public void startMenu() 抛出异常{System.out.println("Hej. Med detta program kan du generera en hemlig nyckel"+"
"+"Vill du:"+"
"+ "1. Generera en nyckel"+"
"+"2. Avsluta");int val=Integer.parseInt(scan.nextLine());做{开关(值){情况 1: generateKey();休息;情况2:System.exit(1);默认值:System.out.println("Du måste välja val 1 eller 2");}}而 (val!=3);}public void generateKey() 抛出异常{尝试 {KeyGenerator gen = KeyGenerator.getInstance("AES");gen.init(128);SecretKey 密钥=gen.generateKey();byte[] keyBytes = key.getEncoded();System.out.print("Ge nyckeln ett filnamn:");字符串文件名 = scan.next();System.out.println("通用nyckeln...");FileOutputStream fileOut = new FileOutputStream(filename);fileOut.write(keyBytes);fileOut.close();System.out.println("Nyckeln ärgenererad med filnamnet: "+filename+"...");System.exit(1);} catch (NoSuchAlgorithmException e) {}}公共静态无效主(字符串 [] args){新的 KeyHandler();}}公共类 EncryptHandler {私人字符串加密数据字符串;私人密码;AlgorithmParameterSpec paramSpec;字节[]四;public EncryptHandler(String dataString, String secretKey, String encryptedDataString){this.encryptedDataString=encryptedDataString;尝试 {encryptFile(dataString,secretKey);} 捕获(异常 e){}}public void encryptFile(String dataString, String secretKey) 抛出异常{FileInputStream fis = new FileInputStream(secretKey);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1){baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");尝试{ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");ecipher.init(Cipher.ENCRYPT_MODE, keySpec);}捕获(例外 e){e.printStackTrace();}System.out.println("正在加密文件...");尝试{encryptStream(new FileInputStream(dataString),new FileOutputStream(encryptedDataString));}捕获(异常 e){e.printStackTrace();}}公共无效加密流(输入流输入,输出流输出){ByteArrayOutputStream bOut = new ByteArrayOutputStream();字节[] buf = 新字节[1024];尝试 {out = new CipherOutputStream(out, ecipher);//读取明文并将其写出int numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}bOut.writeTo(out);关闭();bOut.reset();}捕获 (java.io.IOException e){}}公共静态无效主(字符串 [] args){字符串数据 = "test.txt";字符串 keyFileName="a";String encryptedFile="krypterad.txt";//String encryptedFile =args[2];新的 EncryptHandler(data, keyFileName, encryptedFile);}}公共类 DecryptHandler {公共解密处理程序(){尝试 {解密文件();} 捕获(异常 e){System.out.println("något gick fel :)");}}公共无效解密文件()抛出异常{字节[] buf = 新字节[1024];String keyFilename = "hemlig";FileInputStream fis = new FileInputStream(keyFilename);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1){baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");System.out.println("här");c.init(Cipher.DECRYPT_MODE, keySpec);System.out.println("正在解密文件...");尝试{解密流(新文件输入流(krypterad.txt"),新文件输出流(Dekryperad.txt"),c,buf);}抓住(java.io.IOException e){}System.out.println("文件解密!");}公共无效解密流(输入流输入,输出流输出,密码dcipher,字节[] buf){尝试{in = new CipherInputStream(in, dcipher);//读入解密的字节并将明文写入 outint numRead = 0;while ((numRead = in.read(buf)) >= 0){out.write(buf, 0, numRead);}关闭();}抓住(java.io.IOException e){}}public static void main(String[]args){新的解密处理程序();}}
如果你使用像 CBC 这样的区块链模式,你还需要为 Cipher 提供一个 IvParameterSpec.
所以你可以像这样初始化一个 IvParameterSpec:
//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);
然后为了加密,将您初始化密码的代码更改为:
ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);
以及你解密的地方:
c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);
所以你的完整代码应该是这样的(它对我有用):
公共类 KeyHandler {Scanner scan = new Scanner(System.in);公共 KeyHandler() {尝试 {开始菜单();} 捕获(异常 e){System.out.println("fel någonstanns :)");}}public void startMenu() 抛出异常 {System.out.println("Hej. Med detta program kan du generera en hemlig nyckel" + "
" + "Vill du:" + "
" + "1. Generera en nyckel" + "
" + "2. Avsluta");int val = Integer.parseInt(scan.nextLine());做 {开关(值){情况1:生成密钥();休息;案例2:System.exit(1);默认:System.out.println("Du måste välja val 1 eller 2");}} while (val != 3);}public void generateKey() 抛出异常 {尝试 {KeyGenerator gen = KeyGenerator.getInstance("AES");gen.init(128);SecretKey 密钥 = gen.generateKey();byte[] keyBytes = key.getEncoded();System.out.print("Ge nyckeln ett filnamn:");字符串文件名 = scan.next();System.out.println("通用nyckeln...");FileOutputStream fileOut = new FileOutputStream(filename);fileOut.write(keyBytes);fileOut.close();System.out.println("Nyckeln ärgenererad med filnamnet: " + 文件名 + "...");System.exit(1);} catch (NoSuchAlgorithmException e) {}}公共静态无效主(字符串 [] args){新的 KeyHandler();}}公共类 EncryptHandler {私人字符串加密数据字符串;私人密码;AlgorithmParameterSpec paramSpec;字节[]四;public EncryptHandler(String dataString, String secretKey, String encryptedDataString) {this.encryptedDataString = encryptedDataString;尝试 {encryptFile(dataString,secretKey);} 捕获(异常 e){}}public void encryptFile(String dataString, String secretKey) 抛出异常 {FileInputStream fis = new FileInputStream(secretKey);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1) {baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);尝试 {ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);} 捕获(异常 e){e.printStackTrace();}System.out.println("正在加密文件...");尝试 {encryptStream(new FileInputStream(dataString), new FileOutputStream(encryptedDataString));} 捕获(异常 e){e.printStackTrace();}}公共无效加密流(输入流输入,输出流输出){ByteArrayOutputStream bOut = new ByteArrayOutputStream();字节[] buf = 新字节[1024];尝试 {out = new CipherOutputStream(out, ecipher);//读取明文并将其写出int numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}bOut.writeTo(out);关闭();bOut.reset();} catch (java.io.IOException e) {}}公共静态无效主(字符串 [] args){字符串数据 = "test.txt";String keyFileName = "a";String encryptedFile = "krypterad.txt";//String encryptedFile =args[2];新的 EncryptHandler(data, keyFileName, encryptedFile);}}公共类 DecryptHandler {公共解密处理程序(){尝试 {解密文件();} 捕获(异常 e){e.printStackTrace();System.out.println("något gick fel :)");}}公共无效解密文件()抛出异常{字节[] buf = 新字节[1024];String keyFilename = "hemlig";FileInputStream fis = new FileInputStream(keyFilename);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1) {baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");System.out.println("här");c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);System.out.println("正在解密文件...");尝试 {解密流(新文件输入流(krypterad.txt"),新文件输出流(Dekryperad.txt"),c,buf);} catch (java.io.IOException e) {}System.out.println("文件解密!");}公共无效解密流(输入流输入,输出流输出,密码密码,字节[] buf){尝试 {in = new CipherInputStream(in, dcipher);//读入解密的字节并将明文写入 outint numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}关闭();} catch (java.io.IOException e) {}}公共静态无效主(字符串 [] args){新的解密处理程序();}}
I'm currently working on a function that encrypt/decrypts a specific file with a secret key. I have written three classes, one which generates a key, one which encrypts a file with the key and one that decrypts.
Generating the key and encrypting the file works fine, but when I try to decrypt the file, an exception is thrown at line: c.init(Cipher.DECRYPT_MODE, keySpec);
:
java.security.InvalidKeyException: Parameters missing
I take it I've done something wrong when streaming the secret key to my byte[]
or something is wrong when decrypting the file.
Quick explanation of the three classes: KeyHandler creates a AES key and stores it on the harddrive. The name of the key/plaintext/encrypted/decrypted files is currently hardcoded for testing purposes.
EncryptionHandler
transfers a .txt file on the disk into bytes, encrypts the file with the secret key and then writes the encrypted bytes to the disk using CipherOutputStream
.
DecryptionHandler
of course does the opposite of EncryptionHandler
.
Here's the code:
public class KeyHandler {
Scanner scan = new Scanner(System.in);
public KeyHandler(){
try {
startMenu();
} catch (Exception e) {
System.out.println("fel någonstanns :)");
}
}
public void startMenu() throws Exception{
System.out.println("Hej. Med detta program kan du generera en hemlig nyckel"+"
"+"Vill du:"+"
"+ "1. Generera en nyckel"+"
"+"2. Avsluta");
int val=Integer.parseInt(scan.nextLine());
do{
switch (val){
case 1: generateKey(); break;
case 2: System.exit(1);
default: System.out.println("Du måste välja val 1 eller 2");
}
}
while (val!=3);
}
public void generateKey() throws Exception{
try {
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(128);
SecretKey key=gen.generateKey();
byte[] keyBytes = key.getEncoded();
System.out.print("Ge nyckeln ett filnamn: ");
String filename = scan.next();
System.out.println("Genererar nyckeln...");
FileOutputStream fileOut = new FileOutputStream(filename);
fileOut.write(keyBytes);
fileOut.close();
System.out.println("Nyckeln är genererad med filnamnet: "+filename+"...");
System.exit(1);
} catch (NoSuchAlgorithmException e) {
}
}
public static void main(String[] args){
new KeyHandler();
}
}
public class EncryptHandler {
private String encryptedDataString;
private Cipher ecipher;
AlgorithmParameterSpec paramSpec;
byte[] iv;
public EncryptHandler(String dataString, String secretKey, String encryptedDataString){
this.encryptedDataString=encryptedDataString;
try {
encryptFile(dataString, secretKey);
} catch (Exception e) {
}
}
public void encryptFile(String dataString, String secretKey) throws Exception{
FileInputStream fis = new FileInputStream(secretKey);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int theByte = 0;
while ((theByte = fis.read()) != -1)
{
baos.write(theByte);
}
fis.close();
byte[] keyBytes = baos.toByteArray();
baos.close();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
try
{
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
ecipher.init(Cipher.ENCRYPT_MODE, keySpec);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("Encrypting file...");
try
{
encryptStream(new FileInputStream(dataString),new FileOutputStream(encryptedDataString));
}
catch(Exception e){
e.printStackTrace();
}
}
public void encryptStream(InputStream in, OutputStream out){
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
out = new CipherOutputStream(out, ecipher);
// read the cleartext and write it to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
bOut.writeTo(out);
out.close();
bOut.reset();
}
catch (java.io.IOException e)
{
}
}
public static void main(String[] args){
String data = "test.txt";
String keyFileName="a";
String encryptedFile="krypterad.txt";
//String encryptedFile =args[2];
new EncryptHandler(data, keyFileName, encryptedFile);
}
}
public class DecryptHandler {
public DecryptHandler(){
try {
decryptFile();
} catch (Exception e) {
System.out.println("något gick fel :) ");
}
}
public void decryptFile()throws Exception{
byte[] buf = new byte[1024];
String keyFilename = "hemlig";
FileInputStream fis = new FileInputStream(keyFilename);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int theByte = 0;
while ((theByte = fis.read()) != -1)
{
baos.write(theByte);
}
fis.close();
byte[] keyBytes = baos.toByteArray();
baos.close();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
System.out.println("här");
c.init(Cipher.DECRYPT_MODE, keySpec);
System.out.println("Decrypting file...");
try{
decryptStream(new FileInputStream("krypterad.txt"),new FileOutputStream("Dekryperad.txt"), c, buf);
}
catch (java.io.IOException e){
}
System.out.println("File decrypted!");
}
public void decryptStream(InputStream in, OutputStream out, Cipher dcipher, byte[] buf){
try
{
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0)
{
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e){
}
}
public static void main(String[]args){
new DecryptHandler();
}
}
If you use a block-chaining mode like CBC, you need to provide an IvParameterSpec to the Cipher as well.
So you can initialize an IvParameterSpec like this:
// build the initialization vector. This example is all zeros, but it
// could be any value or generated using a random number generator.
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
Then for encryption, change your code where you init the cipher to this:
ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);
And where you decrypt:
c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);
So your complete code should look like this (It works for me):
public class KeyHandler {
Scanner scan = new Scanner(System.in);
public KeyHandler() {
try {
startMenu();
} catch (Exception e) {
System.out.println("fel någonstanns :)");
}
}
public void startMenu() throws Exception {
System.out.println("Hej. Med detta program kan du generera en hemlig nyckel" + "
" + "Vill du:" + "
" + "1. Generera en nyckel" + "
" + "2. Avsluta");
int val = Integer.parseInt(scan.nextLine());
do {
switch (val) {
case 1:
generateKey();
break;
case 2:
System.exit(1);
default:
System.out.println("Du måste välja val 1 eller 2");
}
} while (val != 3);
}
public void generateKey() throws Exception {
try {
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(128);
SecretKey key = gen.generateKey();
byte[] keyBytes = key.getEncoded();
System.out.print("Ge nyckeln ett filnamn: ");
String filename = scan.next();
System.out.println("Genererar nyckeln...");
FileOutputStream fileOut = new FileOutputStream(filename);
fileOut.write(keyBytes);
fileOut.close();
System.out.println("Nyckeln är genererad med filnamnet: " + filename + "...");
System.exit(1);
} catch (NoSuchAlgorithmException e) {
}
}
public static void main(String[] args) {
new KeyHandler();
}
}
public class EncryptHandler {
private String encryptedDataString;
private Cipher ecipher;
AlgorithmParameterSpec paramSpec;
byte[] iv;
public EncryptHandler(String dataString, String secretKey, String encryptedDataString) {
this.encryptedDataString = encryptedDataString;
try {
encryptFile(dataString, secretKey);
} catch (Exception e) {
}
}
public void encryptFile(String dataString, String secretKey) throws Exception {
FileInputStream fis = new FileInputStream(secretKey);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int theByte = 0;
while ((theByte = fis.read()) != -1) {
baos.write(theByte);
}
fis.close();
byte[] keyBytes = baos.toByteArray();
baos.close();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
// build the initialization vector. This example is all zeros, but it
// could be any value or generated using a random number generator.
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
try {
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Encrypting file...");
try {
encryptStream(new FileInputStream(dataString), new FileOutputStream(encryptedDataString));
} catch (Exception e) {
e.printStackTrace();
}
}
public void encryptStream(InputStream in, OutputStream out) {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
out = new CipherOutputStream(out, ecipher);
// read the cleartext and write it to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
bOut.writeTo(out);
out.close();
bOut.reset();
} catch (java.io.IOException e) {
}
}
public static void main(String[] args) {
String data = "test.txt";
String keyFileName = "a";
String encryptedFile = "krypterad.txt";
//String encryptedFile =args[2];
new EncryptHandler(data, keyFileName, encryptedFile);
}
}
public class DecryptHandler {
public DecryptHandler() {
try {
decryptFile();
} catch (Exception e) {
e.printStackTrace();
System.out.println("något gick fel :) ");
}
}
public void decryptFile() throws Exception {
byte[] buf = new byte[1024];
String keyFilename = "hemlig";
FileInputStream fis = new FileInputStream(keyFilename);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int theByte = 0;
while ((theByte = fis.read()) != -1) {
baos.write(theByte);
}
fis.close();
byte[] keyBytes = baos.toByteArray();
baos.close();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
// build the initialization vector. This example is all zeros, but it
// could be any value or generated using a random number generator.
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
System.out.println("här");
c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);
System.out.println("Decrypting file...");
try {
decryptStream(new FileInputStream("krypterad.txt"), new FileOutputStream("Dekryperad.txt"), c, buf);
} catch (java.io.IOException e) {
}
System.out.println("File decrypted!");
}
public void decryptStream(InputStream in, OutputStream out, Cipher dcipher, byte[] buf) {
try {
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
}
}
public static void main(String[] args) {
new DecryptHandler();
}
}
这篇关于为什么我的 AES 加密会抛出 InvalidKeyException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!