Шифрование AES в Android и дешифрование в nodejs - PullRequest
0 голосов
/ 08 мая 2018

Я пробовал шифрование в Android и дешифрование на сервере nodejs. Я сгенерировал 128-битный ключ AES и зашифровал его, используя алгоритм AES, а затем зашифровал этот сгенерированный ключ, используя алгоритм RSA. Затем отправьте оба на сервер. Но при расшифровке на стороне сервера, я думаю, что расшифровка RSA работает нормально, но есть проблема в расшифровке AES. Я не получаю строку на стороне сервера, которую я зашифровал на стороне клиента.

Это код для шифрования на стороне Android:

String encryptedSecretKey;
String cipherTextString;

// 1. generate secret key using AES
KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);

// 2. get string which needs to be encrypted
String text = "This is the message to be encrypted";

// 3. encrypt string using secret key
byte[] raw = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
cipherTextString = Base64.encodeToString(cipher.doFinal(text.getBytes(Charset.forName("UTF-8"))), Base64.DEFAULT);

// 4. get public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(publicKeyString, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);

// 5. encrypt secret key using public key
Cipher cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedSecretKey = Base64.encodeToString(cipher2.doFinal(secretKey.getEncoded()), Base64.DEFAULT);

Затем отправьте это на сервер.

Код для серверной части приведен ниже:

var encryptedMessage = req.body.cipherText;
var encryptedAesKey = req.body.secretKey;

//printing those values
console.log("\nEncryptedMessage: \n" + encryptedMessage);
console.log("\nEncrypted key: \n" + encryptedAesKey);

var privateKey = fs.readFileSync('././Keys/privkey_server.pem', "utf8");
var bufferForAesKey = new Buffer(encryptedAesKey, "base64");
var obj = {
        key: privateKey
        // , padding: constants.RSA_PKCS1_PADDING
        // , padding: constants.RSA/ECB/OAEPWithSHA-1
};
var decryptedAes = crypto.privateDecrypt(obj, bufferForAesKey);

console.log("Decrypted AES: " + decryptedAes);

var decryptedAesKeyString = decryptedAes.toString("base64");
console.log("Decrypted AES Key: " + decryptedAesKeyString);
var bufferForAES = new Buffer(decryptedAes, "base64");

//decrypting using AES
var bufferForEncryptedMsg = new Buffer(encryptedMessage, "base64");

var decipher = crypto.createDecipher('aes-128-cbc',bufferForAES);
decipher.setAutoPadding(false);
var dec = decipher.update(bufferForEncryptedMsg,"base64", "utf8");
dec += decipher.final("utf8");
console.log(dec);

Здесь конечный результат «dec» не дает правильного результата, но промежуточные результаты одинаковы для клиента и сервера. Это означает, что RSA работает нормально, но есть проблемы в AES.

Выходные данные приведены ниже:

EncryptedMessage: 
SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj


Encrypted key: 
C/pa52PZda3xShrPXkHZx8OL6sW4JBEhG/ggNAoHhSVXIGt+iDq/B1ByG5yStBGF3GFJRQT0aGsG
+bZJydP7j9gTivmt99H/bxiZan4CHZnqfGKG1dJCI7ILAYZMCw7JhIcRC8qHMM4LMdF+rxRhENDe
alUfnsLWpcrX9J6fKejJ7EWnWQ1VadKqCDmrJ5xw0lBbsOpwN/vY09+VhF4WkOz8Y3cQGk+FVdz5
tr4L9/jgXlTZdOC2KVBLSH+9pvtHwMWFKKoDSAzvkil4htBjbWTqlBuEINC4I/J/4P3RX2riT5Pv
xHQi/Dv7vdBlo9AEdvWe3Ek8oBleIpmIQHXwQWknPOYghhBAVmACG/tbEQcAtbcmRLruT/XzjPJt
HNBt2HeG9JHYKNoHC3kOuJdnlGe8mv8k0Nzwj04RhEGKSmPIiu/oDgYwS0l96KIlS2ELqBlS5O0L
AJ+RBG7m0WwC9dfrufsuwu0+SPUmg5/ElXRmA3T81lXtQqQbGg8G6r/bAVFGduy4a49s/VWoylx+
/sI079IwyY0IOfwQTVGZRyDC5O1ZBjoYv2+TRo3bjG8GXNQoybkmWkhgotcqVD9mXO67D2NBsFPT
EJnw+1ApSqR7ggIAF+qsMxejFKBICBL/4J8FP4+obA07J1pWiciTRKX+G130qzIBKM08Zdaf/50=

Decrypted AES: %Kp[ϪS�/�W l��9ӊ˽��~��
B�A�
Decrypted AES Key: JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=
T�Ϝ��u��q�
          ���w�p���u`�̗r[`H0[tW��=��~i-�W

Здесь ключ расшифрованного AES такой же, как ключ, который мы генерируем в Android. Но окончательный вывод не дает желаемого результата. Есть ли ошибка в моем коде ??

1 Ответ

0 голосов
/ 08 мая 2018

Neardupe Дешифрование строк из node.js в Java? , что то же самое в противоположном направлении.

[В Java] я сгенерировал 128-битный ключ AES и зашифровал его с помощью алгоритма AES, а затем зашифровал этот сгенерированный ключ с помощью алгоритма RSA.

Нет, ты не сделал. Ваш Java-код создает экземпляр KeyGenerator для AES-128, но не использует его для генерации ключа. Ключ, который вы фактически использовали (и, как вы говорите, сервер правильно расшифровывается из RSA-OAEP), составляет 32 байта, что соответствует AES-256.

Но ваша главная проблема в том, что createDecipher принимает пароль, а НЕ ключ. По документу

crypto.createDecipher (алгоритм, пароль [, параметры])

Реализация crypto.createDecipher () получает ключи, используя функцию OpenSSL EVP_BytesToKey с алгоритмом дайджеста, установленным на MD5, одной итерацией и без соли.

Вы передали то, что на самом деле является ключом, в качестве пароля; это приводит к тому, что nodejs использует ключ, который полностью отличается от ключа, используемого в Java, и, следовательно, дает совершенно неверные результаты. Вместо этого вы должны использовать createDecipheriv, который действительно берет ключ, и IV (Вектор инициализации).

И это ваша другая проблема. Для дешифрования вы должны использовать тот же IV, что и для шифрования, обычно путем добавления IV к зашифрованному тексту, отправляемому от отправителя к получателю, но вы этого не делаете. В результате следующий (упрощенный) код не может расшифровать первые 16 байтов ваших данных, но делает все остальное.

const crypto = require('crypto');
msg = Buffer.from('SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj','base64');
aeskey = Buffer.from('JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=','base64');
dec = crypto.createDecipheriv('aes-256-cbc',aeskey,Buffer.alloc(16)/*this should be the IV*/);
console.log(dec.update(msg,'','latin1')+dec.final('latin1'));
// I used latin1 instead of utf8 because the garbaged first block 
// isn't valid UTF-8, and the rest is ASCII which works as either.
->
Y;øï«*M2WÚâeage to be encrypted
// some garbaged chars are control chars and Stack (or browser?) 
// may not display them but there really are 16 in total

Кроме того, утверждение в документе, что «векторы инициализации [должны] быть непредсказуемыми и уникальными ... [но не секретными]» является правильным для режима CBC, но не для некоторых других режимов, поддерживаемых OpenSSL (таким образом, nodejs) и Java. Тем не менее, это не программирование Q и, следовательно, оффтоп здесь; он принадлежит к crypto.SX или, возможно, security.SX, где на него уже много раз отвечали.

...