Нужно исправить неправильный метод шифрования в моем C # веб-API - PullRequest
1 голос
/ 11 июня 2019

Мне нужно исправить метод шифрования, написанный на C #.

Во-первых, немного предыстории: я отвечаю за существующее веб-приложение с веб-интерфейсом ecma6 / html и c # web api .net стандарт 4.6.

Имеет много интеграций с разными клиентами для идентификации пользователя. Некоторые интеграции просто переходят к URL-адресу клиента, чтобы выполнить процесс входа в инфраструктуру клиента, а затем возвращаются в приложение с зашифрованным токеном пользователя в строке запроса URL-адреса.

Этот токен зашифрован с использованием шифрования AES256.

Бэкэнд правильно расшифровывает токены, но когда я попытался использовать процедуру шифрования для создания модульного теста, я обнаружил, что что-то не так. Когда я шифрую, а затем дешифрую сообщение, процедура расшифровки выдает следующую ошибку:

Unhandled Exception:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.

Входное сообщение: «ключ1 = значение1; ключ2 = значение2» (без кавычек)

Зашифрованное сообщение, которое я получаю, является NzcrOTc3Kzk3Nys5NzcrOTc3Kzk3Nys5NzcrOVpsVHZ2NzF3NzcrOUZ6UVlRZ3Z2djcxSVlPKy92U0V6NzcrOVNqZFH3N4 * 101B4

Мне нужно исправить ошибку реализации в методе шифрования. Реализация метода расшифровки показывает ожидаемое поведение, и вы заметите двойное декодирование Base64, выполненное на зашифрованной строке: это дано, поскольку мы интегрированы с уже разработанной процедурой шифрования, выполненной клиентом в PERL, который, как мы обнаружили, удвоил кодирование.

Я проверил порядок операций, чтобы увидеть несоответствие между шифрованием и дешифрованием, и мне не удалось обнаружить несоответствие, поэтому нужно обратиться за помощью.

Код, который я синтезировал для этого теста:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

class MainClass {
  public static void Main (string[] args) {
    var secretKey = "This is my secret key";
    var secretIV = "This is my secret iv";
    var originalMessage = "key1=value1;key2=value2";
    var userToken = Cryptography.EncryptAES256CBCBase64x2(originalMessage, secretKey, secretIV);
    Console.WriteLine(userToken);
    var unencryptedToken = Cryptography.DecryptAES256CBCBase64x2(userToken, secretKey, secretIV);
    if (originalMessage == unencryptedToken)
      Console.WriteLine("All fine!");
    else
      Console.WriteLine("Error!");
  }
}

public static class Cryptography
{
  public static string DecryptAES256CBCBase64x2(string base64EncryptedString, string secretKey, string secretIV)
  {
      base64EncryptedString = SaveBase64String(base64EncryptedString);
      var keyBytes = Encoding.UTF8.GetBytes(secretKey);
      var ivBytes = Encoding.UTF8.GetBytes(secretIV);
      var hash = SHA256.Create();
      var keyHash = hash.ComputeHash(keyBytes);
      Array.Resize(ref keyHash, 32);
      var keyHashString = string.Empty;
      foreach (byte x in keyHash)
        keyHashString += string.Format("{0:x2}", x);
      keyHash = Encoding.UTF8.GetBytes(keyHashString.Substring(0, 32));
      var ivHash = hash.ComputeHash(ivBytes);
      Array.Resize(ref ivHash, 16);
      var ivHashString = string.Empty;
      foreach (byte x in ivHash)
        ivHashString += string.Format("{0:x2}", x);
      ivHash = Encoding.UTF8.GetBytes(ivHashString.Substring(0, 16));
      // Create an RijndaelManaged object
      // with the specified key and IV.
      using (var rijAlg = new RijndaelManaged())
      {
        rijAlg.Padding = PaddingMode.PKCS7;
        rijAlg.Mode = CipherMode.CBC;
        rijAlg.Key = keyHash;
        rijAlg.IV = ivHash;
        var encryptedBytes =
          Convert.FromBase64String(
          Encoding.UTF8.GetString(
          Convert.FromBase64String(base64EncryptedString)));
        // Create a decryptor to perform the stream transform.
        var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
        // Create the streams used for decryption.
        using (var msDecrypt = new MemoryStream(encryptedBytes))
        {
            using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
              using (var srDecrypt = new StreamReader(csDecrypt))
              {
                  // Read the decrypted bytes from the decrypting stream
                  // and place them in a string.
                  return srDecrypt.ReadToEnd();
              }
            }
        }
      }
  }

  public static string EncryptAES256CBCBase64x2(string baseString, string secretKey, string secretIV)
  {
      var keyBytes = Encoding.UTF8.GetBytes(secretKey);
      var ivBytes = Encoding.UTF8.GetBytes(secretIV);
      var hash = SHA256.Create();
      var keyHash = hash.ComputeHash(keyBytes);
      Array.Resize(ref keyHash, 32);
      var keyHashString = string.Empty;
      foreach (byte x in keyHash)
        keyHashString += string.Format("{0:x2}", x);
      keyHash = Encoding.UTF8.GetBytes(keyHashString.Substring(0, 32));
      var ivHash = hash.ComputeHash(ivBytes);
      Array.Resize(ref ivHash, 16);
      var ivHashString = string.Empty;
      foreach (byte x in ivHash)
        ivHashString += string.Format("{0:x2}", x);
      ivHash = Encoding.UTF8.GetBytes(ivHashString.Substring(0, 16));
      // Create an RijndaelManaged object
      // with the specified key and IV.
      using (var rijAlg = new RijndaelManaged())
      {
        rijAlg.Padding = PaddingMode.PKCS7;
        rijAlg.Mode = CipherMode.CBC;
        rijAlg.Key = keyHash;
        rijAlg.IV = ivHash;
        var encryptedBytes = Encoding.UTF8.GetBytes(baseString);
        // Create a encryptor to perform the stream transform.
        var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
        // Create the streams used for encryption.
        using (var msEncrypt = new MemoryStream(encryptedBytes))
        {
            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Read))
            {
              using (var srEncrypt = new StreamReader(csEncrypt))
              {
                  // Read the encrypted bytes from the encrypting stream
                  // and place them in a string.
                  var result = srEncrypt.ReadToEnd();

                  return Convert.ToBase64String(
                  Encoding.UTF8.GetBytes(
                  Convert.ToBase64String(
                  Encoding.UTF8.GetBytes(result))));
              }
            }
        }
      }
  }
  public static string SaveBase64String(string data)
  {
      data = data.Replace("-", "+").Replace("_", "/");
      var mod = data.Length % 4;
      if (mod > 2)
        mod = 1;
      return data + string.Empty.PadRight(mod, '=');
  }
}

По следующей ссылке вы можете попробовать онлайн-пример: https://repl.it/@ormasoftchile/Test-encrypt-decrypt

Спасибо всем.

1 Ответ

1 голос
/ 12 июня 2019

В текущем коде зашифрованный текст хранится в строке (StreamReader.ReadToEnd), которая, как правило, не работает, так как при этом данные повреждены.Вместо этого зашифрованный текст должен храниться в байтовом массиве, который при необходимости может быть закодирован в Base64.

Чтобы устранить проблему

  • удалите строку:

    var encryptedBytes = Encoding.UTF8.GetBytes(baseString);  
    
  • и замените весь блок MemoryStream на:

    using (var msEncrypt = new MemoryStream())
    {
        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(baseString);
            }
            var encryptedBytes = msEncrypt.ToArray();
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(Convert.ToBase64String(encryptedBytes)));
        }
    }
    

Другим моментом является двойное кодирование / декодирование Base64.Это не имеет смысла и просто избыточно и снижает производительность.Если возможно, это следует изменить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...