我已經「繼承」了一個Ruby on Rails應用程序,並且我必須將此應用程序從Ruby轉換爲Java,並且最重要的是,我沒有與創作者。AES-256:在Ruby和Java實現之間的IV矢量誤解
我的問題是在AES-256認證中的IV矢量。 Ruby應用程序使用AESCrypt gem來加密和解密用戶的密碼。它工作正常,我已經有成千上萬的用戶在數據庫中。
問題是,當我嘗試在Java中做同樣的事情時(我已經更新了JCE以允許256位密鑰長度)。 Key和IV在ruby源代碼中被寫成二進制字符串(見下文),當我嘗試在Java中使用它時,我得到一個異常,它說IV長度必須是16字節長(我知道它必須是長度爲16個字節,但Ruby中的二進制字符串有32個字符)。
Ruby代碼(正常工作):
require 'openssl'
require 'digest/md5'
require 'base64'
module AESCrypt
KEY = "AB1CD237690AF13B6721AD237A"
IV = "por874hyufijdue7w63ysxwet4320o90"
TYPE = "AES-256-CBC"
def AESCrypt.key(key)
key = Digest::MD5.hexdigest(key)
key.slice(0..32)
end
# Encrypts a block of data given an encryption key and an
# initialization vector (iv). Keys, iv's, and the data returned
# are all binary strings. Cipher_type should be "AES-256-CBC",
# "AES-256-ECB", or any of the cipher types supported by OpenSSL.
# Pass nil for the iv if the encryption type doesn't use iv's (like
# ECB).
#:return: => String
#:arg: data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.encrypt(data)
return nil if data.nil?
return data if data.blank?
aes = OpenSSL::Cipher::Cipher.new(TYPE)
aes.encrypt
aes.key = AESCrypt.key(KEY)
aes.iv = IV if IV != nil
result = aes.update(data) + aes.final
Base64.encode64(result)
end
end
,這是我的Java代碼(它應該做的一樣,似乎有16個字符的工作/字節IV):
public static void main(String[] args) throws UnsupportedEncodingException {
String KEY = "AB1CD237690AF13B6721AD237A";
String IV = "por874hyufijdue7w63ysxwet4320o90";
SecretKeySpec key = generateKey(KEY);
String message = "password";
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] ciphedText = cipher.doFinal(message.getBytes());
String encoded = Base64.encodeBase64String(ciphedText);
System.out.println("ENCRYPTED text= " + encoded);
}
public static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
final MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = password.getBytes("UTF-8");
digest.update(bytes, 0, bytes.length);
byte[] key = digest.digest();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
return secretKeySpec;
}
我得到這個例外(顯然):
java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:516)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:339)
at javax.crypto.Cipher.implInit(Cipher.java:801)
at javax.crypto.Cipher.chooseProvider(Cipher.java:859)
at javax.crypto.Cipher.init(Cipher.java:1370)
at javax.crypto.Cipher.init(Cipher.java:1301)
at com.javi.test.security.Test.main(Test.java:129)
我想我的問題是我轉換字節[]中的IV Java字符串的方式。我認爲ruby中的openSSL代碼是將IV的32個字節解包(或內部執行)到16個字節。我嘗試了很多東西,但我要瘋了。
任何人都有同樣的問題或找出哪裏可能是我的問題? 我已經發布了加密代碼,但我解密相同的問題。
在此先感謝,我會非常感謝每一個答案。 :)
我不知道ruby/openssl是如何操作的,但可能只有前16個字符默默地用於IV。 –
我剛剛完成了考試,只考慮了我的IV字符串的拳頭16個字符。我加密的文本是「123456」,ruby app的加密文本是「APkjtkW8yg4ibXhc/OgO3w ==」,而java的加密文本是「n6ZD4972iputzGCstjifXw ==」。他們不匹配:(也許早期的KEY代碼不適用於它,應該是我新加密的。無論如何感謝@ArtjomB。 –
您是否在Ruby代碼中編碼UTF-8字符串?因爲Java是UTF-8默認情況下,UTF-8字符串的編碼方式不同於ASCII /拉丁字符串 – mcfinnigan