#java #aes #cryptojs
#java #aes #cryptojs
Вопрос:
Я зашифровал сообщение с помощью cryptojs aes 256 на стороне клиента. Но не удалось расшифровать его на стороне java. Сначала я передаю ключ непосредственно на стороне сервера в виде шестнадцатеричного, затем преобразую его из шестнадцатеричного в java bytearray. Это не сработало. Затем я передаю фразу, соль, iv на сервер как шестнадцатеричную. Затем сгенерируйте ключ. Это все равно не сработало. Всегда жаловаться на неправильную длину ключа.
На стороне клиента:
var salt = CryptoJS.lib.WordArray.random(16);
var salt_hex = CryptoJS.enc.Hex.stringify(salt);
var iv = CryptoJS.lib.WordArray.random(256/32);
var iv_hex = CryptoJS.enc.Hex.stringify(iv);
var key = CryptoJS.PBKDF2(secret, salt, { keySize: 256/32, iterations: 10 });
var key_hex=CryptoJS.enc.Hex.stringify(key);
var encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv: iv });
var encryptedtxt = secret ":" salt_hex ":" iv_hex ":" encrypted.ciphertext.toString(CryptoJS.enc.Base64) ":" key_hex;
На стороне сервера:
if (encrypted != null)
{
//Get the passphras, salt, IV and msg
String data[] = encrypted.split(":");
String passphrase = data[0];
String salt_hex = data[1];
String iv_hex = data[2];
String msg64 = data[3];
String jskey_hex = data[4];
byte[] jskey = hexStringToByteArray(jskey_hex);
byte[] iv = hexStringToByteArray(iv_hex);
byte[] salt = hexStringToByteArray(salt_hex);
BASE64Decoder decoder = new BASE64Decoder();
byte[] msg = decoder.decodeBuffer(msg64);
try {
//theClear = AES.decrypt(encrypted);
/* Decrypt the message, given derived key and initialization vector. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), salt, 10, 256/32);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(msg), "UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Комментарии:
1. Если «длина ключа неправильная», то вашей проблемой могут быть начальные нули.
stringify()
Преобразуется ли метод[0x01, 0x02, 0x03]
в"123"
? Ваш код дешифрования, вероятно, предполагает"010203"
."123"
вероятно, выдаст двухбайтовый массив,[0x12, 0x03]
, который не соответствует входным данным и имеет неправильную длину. Это фатально для криптографического ключа.2.
256/32 == 8
, в то время как поддерживаемые размеры ключей для AES составляют 16, 24 или 32 байта. Вам нужно будет изменить как JS, так и Java-код, чтобы использовать ключ размером не менее 16 байт.3. rossum — шестнадцатеричный строковый ключ похож на 010203. Но я выполняю шестнадцатеричное декодирование на стороне java в массив байтов. Интересно, как слово array на JS сопоставляется с массивом байтов на java?
4. Ваш IV также имеет неправильный размер в CryptoJS. AES использует 128-битные блоки, поэтому IV также должен быть 128 бит.
5. Оулстед — Вы абсолютно правы насчет капельницы. Изменение этого.
Ответ №1:
Наконец-то разобрался. По умолчанию JRE 7 не поддерживает 256-битный ключ. Мне пришлось загрузить новые банки с http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html и перезапишите их в папке jre/lib/security. Вам придется сделать то же самое для Websphere 6 или 7. Если вы этого не сделаете, появится запрос «недопустимый размер ключа». Я также видел «недопустимый размер ключа x», где x — число. Это означает, что размер ключа неверен. Ниже приведен код.
На стороне сервера:
//@Override
public String getClearText() throws IOException {
// Get the body
String encrypted = super.getParameter("aes"); //base64
if (encrypted != null)
{
//Get the passphras, salt, IV and msg
String data[] = encrypted.split(":");
String passphrase = data[0];
String salt_hex = data[1];
String iv_hex = data[2];
String msg64 = data[3];
String jskey_hex = data[4];
byte[] jskey = hexStringToByteArray(jskey_hex);
byte[] iv = hexStringToByteArray(iv_hex);
byte[] salt = hexStringToByteArray(salt_hex);
BASE64Decoder decoder = new BASE64Decoder();
byte[] msg = decoder.decodeBuffer(msg64);
String plaintext = "";
try {
SecretKey key = new SecretKeySpec(jskey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
plaintext = new String(cipher.doFinal(msg), "UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("in filter, decrypted: " plaintext);
}
return plaintext;
}
Клиент:
$(function() {
$('#test').on('submit', function() {
var plaintext = $('#text').val();
var secret = '0123456789abcdef';
var salt = CryptoJS.lib.WordArray.random(16);
var salt_hex = CryptoJS.enc.Hex.stringify(salt);
var iv = CryptoJS.lib.WordArray.random(16);
var iv_hex = CryptoJS.enc.Hex.stringify(iv);
var key = CryptoJS.PBKDF2(secret, salt, { keySize: 256/32, iterations: 1 });
//var key_hex=CryptoJS.enc.Hex.stringify(key);
var key_hex= key;
var encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv: iv });
//decrypt
var decrypted = CryptoJS.AES.decrypt(
encrypted,
CryptoJS.enc.Hex.parse(key_hex),
{ iv: CryptoJS.enc.Hex.parse(iv_hex) });
var text = decrypted.toString( CryptoJS.enc.Utf8 );
//console.log(encrypted);
// ----- base64 encoding ----------
var encryptedtxt = secret ":" salt_hex ":" iv_hex ":" encrypted.ciphertext.toString(CryptoJS.enc.Base64) ":" key_hex;
console.log('html - ciphere txt : ' encryptedtxt);
// ---- testing ----
//var decrypted = CryptoJS.AES.decrypt(encrypted, key,{iv: CryptoJS.enc.Utf8.parse(iv)});
//console.log(decrypted.toString(CryptoJS.enc.Utf8));
post ('/E2Efilter/TheServlet', encryptedtxt);
return false;
});
Комментарии:
1. Похоже, что вы храните свой ключ со всеми другими параметрами (iv / salt / зашифрованные данные), так почему же вы зашифровали в первую очередь? Злоумышленник может расшифровать данные так же легко.