Java でパスフレーズを使用して、あるファイルの内容を別のファイルに暗号化しようとしています。ファイルはバイト配列に読み取られ、別のバイト配列に暗号化されてから、新しいファイルに書き込まれます。残念ながら、暗号化を逆にしようとすると、出力ファイルがガベージとして復号化されます。
この問題は、同じパスフレーズが使用されるたびに同じキーを生成することに関係していると強く思います。キーが生成されるたびにキーをファイルにダンプするテスト方法を作成しました。キーは、直接およびエンコードされた形式で記録されます。前者は毎回同じですが、後者はなぜかいつも違います。
正直なところ、私は暗号化方式について、特に Java についてはあまり知りません。データが適度に安全であることだけが必要であり、暗号化は、かなりの時間とスキルを持つ人からの攻撃に耐える必要はありません。これについてアドバイスをくれた人には、事前に感謝します。
編集: Esailija は親切にも、私が常に ENCRYPT_MODE で暗号を設定していたことを指摘してくれました。ブール引数を使用して問題を修正しましたが、次の例外が発生しています。
javax.crypto.IllegalBlockSizeException: パディングされた暗号で復号化する場合、入力の長さは 8 の倍数でなければなりません
パスフレーズが適切に使用されていないように思えます。私は、「PBEWithMD5AndDES」がそれを 16 バイトのコードにハッシュするという印象を受けました。これは、8 の倍数であることが最も確実です。キーが生成され、暗号化モードで問題なく使用されるのはなぜだろうかと思っていますが、試してみると問題が発生します。まったく同じ条件で復号化します。
import java.various.stuff;
/**Utility class to encrypt and decrypt files**/
public class FileEncryptor {
//Arbitrarily selected 8-byte salt sequence:
private static final byte[] salt = {
(byte) 0x43, (byte) 0x76, (byte) 0x95, (byte) 0xc7,
(byte) 0x5b, (byte) 0xd7, (byte) 0x45, (byte) 0x17
};
private static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException{
//Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
//Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
/*Dump the key to a file for testing: */
FileEncryptor.keyToFile(key);
//Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
//Set the cipher mode to decryption or encryption:
if(decryptMode){
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**Encrypts one file to a second file using a key derived from a passphrase:**/
public static void encryptFile(String fileName, String pass)
throws IOException, GeneralSecurityException{
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, false);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
decData = new byte[(int)inFile.length()];
inStream.read(decData);
inStream.close();
//Encrypt the file data:
encData = cipher.doFinal(decData);
//Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(new File(fileName + ".encrypted"));
outStream.write(encData);
outStream.close();
}
/**Decrypts one file to a second file using a key derived from a passphrase:**/
public static void decryptFile(String fileName, String pass)
throws GeneralSecurityException, IOException{
byte[] encData;
byte[] decData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, true);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
//Decrypt the file data:
decData = cipher.doFinal(encData);
//Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + ".decrypted.txt"));
target.write(decData);
target.close();
}
/**Record the key to a text file for testing:**/
private static void keyToFile(SecretKey key){
try {
File keyFile = new File("C:\\keyfile.txt");
FileWriter keyStream = new FileWriter(keyFile);
String encodedKey = "\n" + "Encoded version of key: " + key.getEncoded().toString();
keyStream.write(key.toString());
keyStream.write(encodedKey);
keyStream.close();
} catch (IOException e) {
System.err.println("Failure writing key to file");
e.printStackTrace();
}
}
}