Исключение дешифрования RSA: длина данных для дешифрования недопустима для размера этого ключа - PullRequest
3 голосов
/ 17 марта 2020

У меня есть Angular + Net Core-приложение с зашифрованным соединением (RSA + AES). Все запросы от клиента приходят через POST. (Ниже приведен пример.

Приведенный ниже скрипт работает довольно хорошо, но в 5% случаев выдает исключение:

Длина данных для расшифровки недопустима для размера этого ключа в строке:

var decryptedAesKey = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.k), RSAEncryptionPadding.Pkcs1));

Часть шифрования (Front-end)

encrypt(requestObj:any):any {  
var rsaEncrypt = new JsEncryptModule.JSEncrypt();
var key = this.generateAesKey(32); //secret key
var iv = this.generateAesKey(16); //16 digit

var stringifiedRequest = CryptoJS.enc.Utf8.parse(JSON.stringify(requestObj));
var aesEncryptedRequest = CryptoJS.AES.encrypt(stringifiedRequest, 
CryptoJS.enc.Utf8.parse(key), 
{ 
  keySize: 128 / 8,
  iv: CryptoJS.enc.Utf8.parse(iv),
  padding: CryptoJS.pad.Pkcs7,
  mode: CryptoJS.mode.CBC
 });

rsaEncrypt.setPrivateKey(this.publicPemKey);
var encryptedKey = rsaEncrypt.encrypt(key);
var encryptedIV  = rsaEncrypt.encrypt(iv);

var encryptedRequestObj = {
    k: encryptedKey,
    v: encryptedIV,
    r: aesEncryptedRequest.toString()
 };

return encryptedRequestObj;

}

Часть расшифровки (C# Back-end)

var decryptedAesKey = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.k), 
RSAEncryptionPadding.Pkcs1));
var decryptedAesIV = Encoding.UTF8.GetString(rsaCng.Decrypt(Convert.FromBase64String(request.v), RSAEncryptionPadding.Pkcs1));

byte[] encryptedBytes = request.r;
AesCryptoServiceProvider aes = new AesCryptoServiceProvider()
{
    Mode = CipherMode.CBC,
    Padding = PaddingMode.PKCS7,
    Key = Encoding.UTF8.GetBytes(decryptedAesKey),
    IV = Encoding.UTF8.GetBytes(decryptedAesIV)
};

ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();

requestJson = Encoding.UTF8.GetString(secret);

Пример , пользователь хочет открыть страницу по идентификатору.

Front-end:
1) шифрует Id запроса с помощью AES
2) шифрует ключ AES и iv с использованием RSA
3) отправляет на сервер

Back -end:
1) расшифровывает ключ и значение AES, используя RSA <--- BREAKS ЗДЕСЬ <br>2) расшифровывает Id запроса, используя ключ AES & iv
3) расшифровывает и получает идентификатор, как если бы не было шифрования

Этот лог c работает довольно хорошо, но иногда ломается ...

ПРИМЕР ОТКАЗА:

{ "k":"L+ikMb/JGvFJmhBpADMGTVLFlkHOe69dZUVSQ5r7yHCvWSwY2x6KMR274ByflF0lDMYdCmywo+Nfq6JUybRctDqmAp8UFHXnhwBAv49d99mF5x2yGbJr/j0cn6EZyhweNK4p97i5yMM6MQtluZTIErpsUa22Cajtj8F+xl0jJPUMXIf8cs2X+ooFr5VP/p/vlbPmnEY3K/hMCRZRdXMkEqaCWoA5EnYMTQABtRXPZWgLSQwJpr4dqEAhGCBtga1AGsKF3dQCsKO92NYyst0ngkBiKwFNfy1QDwbk4SzKAKeBckaY17SHt526NMvpEv08BGV6btBxcM+ypsmpB4o0",
"v":"LIndJOjUgKHDlXqwpg7uSmDuut3oi5z9L/GKm2KgU7P2EXmf/JIpXM0JgpTXPJL7wUTndq3F9UMlMdU70JBOV56x/4uIBRbHbyvaG2JZYxbBZblwyYgdo1ZcK1OSE4k5oesQmMEGNEk9RVu+EZO4xAme6+mlyd2/Y/709jaC90PuiOG/k/4JMTTI/2q4s7tk6IgSxLBT8ZiOtgJVGdasSaAksEBMRHyUkzAIr5tSUw1VXedwJFPfwQT2nOD5dU2cxiNJKOwtO9uAYXly0U0FDoa/nkWskca8zaU+4EiPikJ6Km7phViH9JvwZFgHhBj+8FM6Jof+AdrY3q1dcMLFlg==",
"r":"OJnA3wFoKKG+iu4FciXyJg=="
}

ПРИМЕР ПРАВИЛЬНОГО ЗАПРОСА: * 105 1 *

{   "k":"uW8d7vIzlgkEkKTkDnHbBZeqKwdgoG+1BVZ/NUiC0pZ/LqZM9aUasQSx+qDg+X50ur30uRnEyAyIZXruYeHQb8cacx5mvr9LWLud+wueJXsOlEEdocD/4A1DfE9TDFdnTaVcMSIwhSVlLPUjO7ubJdANY9yK4S+vb0IyPbsrYpAT7ho01mDkvsH1rZsId/TmzQadmsGhThowu+mrQlz78rrdlN8nI5LnUQHXRNWMUgBvuteTpVBmyrfnIELIKoo/jI6Nj4rGPQBf7+2OOoZPs0Y1GtjXxUCTAt7madNLKSOdaPjdWjaOfGSwnymDNeEFyJQOmAwHZoOGYNd2B/UhQQ==",
"v":"IimiJFcKv5ZHWHljJixX0LUgV4I2GWAWPbk7dWHVhwmHEhTHA/hCdih/E1wiWFS+0KaL05ZobiZInyK7gCwYPHaz0aRCSQtVeBPiFg4f7L0gwfvk1GHwJ1wZjqNJZaYf0elXJzc2l5BwN+aXNWaNJDPA7M6kfK6UPkq84IV3ohCQcTuC8zPM7aMJHxpz9IudcrMmYIkeqrj9Do88CkTLv8yg5hk3EASPk9HqsUieuQixggv/8ZlHnp00iftc62LJlIuCkGn4WR3FkMdFdqpKXf6Ebj8PU1HOmokEtKtYJiOZ5JxieZO5Pnd+ez6sO7khIbdRFDhAQ20chsxKUypezw==",
"r":"2mbUgU44JFFDlWu8As2RIw=="
}

1 Ответ

2 голосов
/ 17 марта 2020

В случае неудачного запроса декодированный зашифрованный ключ AES Base64 имеет длину 255 байтов. Для 2048-битного ключа RSA это должно быть 256 байтов, как и для остальных данных.

Для RSA-шифрования JSEncrypt используется с известной ошибкой, которая время от времени вызывает слишком короткие шифротексты и которая, вероятно, является причиной вашей проблемы, см. здесь . Эта ошибка была открыта в июле 2019 года и еще не исправлена.

В JSEncrypt слишком короткие шифротексты обрабатываются правильно, поэтому ошибки не возникает. Кроссплатформенность, однако, это часто не так, потому что слишком короткие шифротексты, строго говоря, недействительны, и поэтому некоторые языки программирования идентифицируют их как недействительные, например, Python, очевидно, C# - другой.

Если слишком короткий зашифрованный текст вручную дополняется слева до длины модуля с помощью 0x00, зашифрованный текст также должен быть дешифруемым в коде C#.

Обновление:

  • У меня успешно проверено предлагаемое исправление с использованием вашего кода. Зашифрованный текст может быть исправлен в коде JavaScript или C#. Возможная реализация для стороны JavaScript, например, для ключа:

    encryptedKey = btoa(atob(encryptedKey).padStart(256, "\0"));
    

    , где encryptedKey - шифрованный текст в кодировке Base64, возвращаемый JSEncrypt#encrypt. Чтобы убедиться, что это исправление не применяется к зашифрованным текстам, которые уже имеют правильную длину, полезна проверка длины: зашифрованный в Base64 зашифрованный текст длиной 4 * Math.ceil(256 / 3) не нужно фиксировать, поскольку он соответствует зашифрованному тексту правильной длины 256 байтов, см. здесь .

  • Вы применяете метод setPrivateKey в части JSEncrypt при установке ключа publi c для шифрования правильным будет setPublicKey, см. здесь . Однако JSEncrypt , кажется, исправляет это внутренне, потому что это работает также. Тем не менее, это должно быть изменено, потому что это вводит в заблуждение.

  • Как уже упоминалось в комментариях @kelalaka, IV не является секретом и не нуждается в шифровании.

...