AES-Java中的简单加密,使用openssl解密

我正在尝试使用Java Cryto在Java中进行简单的AES加密,然后可以使用OpenSSL在ObjectiveC中对其进行解密。

因为我没有在ObjectiveC方面进行操作,所以我想使用openSSL命令行确保它可以正常工作,但是我总是会收到“错误的魔术数字”

这是我的Java代码

public class EncryptionUtils {

private static final String AES_CIPHER_METHOD = "AES";

private static final int AES_KEY_SIZE = 128;

public static byte[] generateAesKey() throws NoSuchAlgorithmException {

KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_CIPHER_METHOD);

keyGenerator.init(AES_KEY_SIZE);

SecretKey key = keyGenerator.generateKey();

return key.getEncoded();

}

public static SecretKeySpec createAesKeySpec(byte[] aesKey) {

return new SecretKeySpec(aesKey, AES_CIPHER_METHOD);

}

public static void aesEncryptFile(File in, File out, SecretKeySpec aesKeySpec) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {

Cipher aesCipher = Cipher.getInstance(AES_CIPHER_METHOD);

aesCipher.init(Cipher.ENCRYPT_MODE, aesKeySpec);

InputStream inputStream = new FileInputStream(in);

try {

OutputStream outputStream = new CipherOutputStream(new FileOutputStream(out), aesCipher);

try {

IOUtils.copy(inputStream , outputStream);

} finally {

outputStream.close();

}

} finally {

inputStream.close();

}

}

}

//testcode

@Test

public void testAesEncryptFile() throws IOException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {

byte[] aesKey = EncryptionUtils.generateAesKey();

SecretKeySpec aesKeySpec = EncryptionUtils.createAesKeySpec(aesKey);

EncryptionUtils.aesEncryptFile(new File("C:\\test\\test.txt"), new File("C:\\test\\test-encrypted.txt"), aesKeySpec);

FileOutputStream outputStream = new FileOutputStream("C:\\test\\aes.key");

outputStream.write(aesKey);

outputStream.close();

}

@Test

public void testAesDecryptFile() throws IOException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {

FileInputStream keyFis = new FileInputStream("C:\\test\\aes.key");

ByteArrayOutputStream keyBaos = new ByteArrayOutputStream();

IOUtils.copy(keyFis, keyBaos);

SecretKeySpec keySpec = new SecretKeySpec(keyBaos.toByteArray(), "AES");

Cipher cipher = Cipher.getInstance("AES");

cipher.init(Cipher.DECRYPT_MODE, keySpec);

FileInputStream fileInputStream = new FileInputStream("C:\\test\\test-encrypted.txt");

ByteArrayOutputStream baos = new ByteArrayOutputStream();

IOUtils.copy(fileInputStream, baos);

byte[] decrypted = cipher.doFinal(baos.toByteArray());

FileOutputStream outputStream = new FileOutputStream("C:\\test\\test-decrypted.txt");

outputStream.write(decrypted);

outputStream.close();

}

现在可以按预期运行,文件“ test-encrypted.txt”确实已加密,并且“ test-decrypted.txt” ==“ test.txt”

然后,我尝试使用OpenSSL在命令行上运行解密

openssl enc -d -aes-128-ecb -in test-encrypted.txt -k aes.key

但是,这总是给我

bad magic number

从我可以看到,Java中的使用算法“ AES”默认情况下使用“ ECB”模式,因此上述方法应该可以工作。我究竟做错了什么。

回答:

问题确实是由于OpenSSL从密码计算出的密钥所致。

原因很可能是OpenSSL拥有自己的算法来从密码派生密钥EVP_BytesToKey,这与Java的算法不同。

我发现的唯一解决方案是使用该算法的Java重新实现:

private static final int KEY_LENGTH = 32;    

private byte[] deriveKey(String encryptionPassword, byte[] salt) throws NoSuchAlgorithmException {

final byte[] passAndSalt = ArrayUtils.addAll(encryptionPassword.getBytes(), salt);

byte[] hash = new byte[0];

byte[] keyAndIv = new byte[0];

for (int i = 0; i < 3 && keyAndIv.length < KEY_LENGTH; i++) {

final byte[] dataToHash = ArrayUtils.addAll(hash, passAndSalt);

final MessageDigest md = MessageDigest.getInstance("SHA-256");

hash = md.digest(dataToHash);

keyAndIv = ArrayUtils.addAll(keyAndIv, hash);

}

return Arrays.copyOfRange(keyAndIv, 0, KEY_LENGTH);

}

ArrayUtils 是Apache Commons库的一部分。

完整用法:

IvParameterSpec initializationVectorSpec = new IvParameterSpec(

Hex.decodeHex(encryptionInitializationVector.toCharArray()));

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

byte[] salt = new SecureRandom().generateSeed(8);

byte[] key = deriveKey(encryptionPassword, salt);

Key keySpec = new SecretKeySpec(key, "AES");

cipher.init(Cipher.ENCRYPT_MODE, keySpec, initializationVectorSpec);

byte[] rawEncryptedInput = cipher.doFinal(input.getBytes());

byte[] encryptedInputWithPrependedSalt = ArrayUtils.addAll(ArrayUtils.addAll(

"Salted__".getBytes(), salt), rawEncryptedInput);

return Base64.getEncoder()

.encodeToString(encryptedInputWithPrependedSalt);

以上是 AES-Java中的简单加密,使用openssl解密 的全部内容, 来源链接: utcz.com/qa/410617.html

回到顶部