gpt4 book ai didi

Java用密码加密文件

转载 作者:行者123 更新时间:2023-12-02 09:08:37 24 4
gpt4 key购买 nike

您好,我是新用户,这是我的第一个问题:我声明我对密码学没有广泛的了解。我正在尝试使用用户提供的密码加密文件,并且找到了此方法:

fileProcessor(Cipher.ENCRYPT_MODE,key,inputFile,newFile);

static void fileProcessor(int cipherMode,String key,File inputFile,File outputFile) {
try {
Key secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(cipherMode, secretKey);

FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);

byte[] outputBytes = cipher.doFinal(inputBytes);

FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);

inputStream.close();
outputStream.close();

} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException e) {
e.printStackTrace();
}
}

问题是该程序仅在我输入 16 字节密码时才有效(我认为即使是它的倍数也可以)。如何使用不一定是 16 字节倍数的密码?

最佳答案

key (SecretKeySpec) 是一个加密 key ,而不是用户提供的简单明文密码。 AES 标准指定以下 key 大小:128、192 或 256 位。可以使用 key 派生函数从文本密码创建 key ,例如 PBKDF2 .

Maarten-reinstateMonica评论中提到,Cipher.getInstance("AES") 会导致 ECB 模式下的 AES 加密,即 insecureAES-GCM强烈认可authenticated encryption基于AES算法的模式。

此外,在继续使用示例代码之前,您需要了解以下概念:

示例代码:

// The number of times that the password is hashed during the derivation of the symmetric key
private static final int PBKDF2_ITERATION_COUNT = 300_000;
private static final int PBKDF2_SALT_LENGTH = 16; //128 bits
private static final int AES_KEY_LENGTH = 256; //in bits
// An initialization vector size
private static final int GCM_NONCE_LENGTH = 12; //96 bits
// An authentication tag size
private static final int GCM_TAG_LENGTH = 128; //in bits

private static byte[] encryptAES256(byte[] input, String password) {
try {
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
// Derive the key, given password and salt
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
// A salt is a unique, randomly generated string
// that is added to each password as part of the hashing process
byte[] salt = new byte[PBKDF2_SALT_LENGTH];
secureRandom.nextBytes(salt);
KeySpec keySpec =
new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATION_COUNT, AES_KEY_LENGTH);
byte[] secret = factory.generateSecret(keySpec).getEncoded();
SecretKey key = new SecretKeySpec(secret, "AES");

// AES-GCM encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// A nonce or an initialization vector is a random value chosen at encryption time
// and meant to be used only once
byte[] nonce = new byte[GCM_NONCE_LENGTH];
secureRandom.nextBytes(nonce);
// An authentication tag
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);
byte[] encrypted = cipher.doFinal(input);
// Salt and nonce can be stored together with the encrypted data
// Both salt and nonce have fixed length, so can be prefixed to the encrypted data
ByteBuffer byteBuffer = ByteBuffer.allocate(salt.length + nonce.length + encrypted.length);
byteBuffer.put(salt);
byteBuffer.put(nonce);
byteBuffer.put(encrypted);
return byteBuffer.array();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static byte[] decryptAES256(byte[] encrypted, String password) {
try {
// Salt and nonce have to be extracted
ByteBuffer byteBuffer = ByteBuffer.wrap(encrypted);
byte[] salt = new byte[PBKDF2_SALT_LENGTH];
byteBuffer.get(salt);
byte[] nonce = new byte[GCM_NONCE_LENGTH];
byteBuffer.get(nonce);
byte[] cipherBytes = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherBytes);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec keySpec =
new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATION_COUNT, AES_KEY_LENGTH);
byte[] secret = factory.generateSecret(keySpec).getEncoded();
SecretKey key = new SecretKeySpec(secret, "AES");

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// If encrypted data is altered, during decryption authentication tag verification will fail
// resulting in AEADBadTagException
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
return cipher.doFinal(cipherBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static void main(String[] args) throws Exception {
String password = "Q8yRrM^AvV5r8Yx+"; //Password still has to be strong ehough
String input = "Sample text to encrypt";
byte[] encrypted = encryptAES256(input.getBytes(UTF_8), password);
System.out.println(Base64.getEncoder().encodeToString(encrypted));
//s+AwwowLdSb3rFZ6jJlxSXBvzGz7uB6+g2e97QXGRKUY5sHPgf94AOoybkzuR3rNREMj56Ik1+Co682s4vT2sAQ/
byte[] decrypted = decryptAES256(encrypted, password);
System.out.println(new String(decrypted, UTF_8));
//Sample text to encrypt
}

关于 random nonces 的更多信息。如果只有少数记录使用相同的 key 加密,则随机数不会带来风险。但是,如果使用同一 key 对大量记录进行加密,则风险可能会变得相关。

A single repeated nonce is usually enough to fully recover the connection’s authentication key. In such faulty implementations, authenticity is lost and an attacker is able to manipulate TLS-protected content.

出于安全原因,应避免随机随机数并应使用计数器。

关于Java用密码加密文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59592205/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com