Шифрование и дешифрование с помощью Bouncy Castle на c # и php

#c# #php #encryption #cryptography #bouncycastle

#c# #php #шифрование #криптография #bouncycastle

Вопрос:

Я использую bouncy castle и следующий код на c # для шифрования и дешифрования данных на c#

 public static string BCEncrypt(string input)
{
    string keyString = "mysecretkey12345";
    string keyStringBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(keyString));
    byte[] inputBytes = Encoding.UTF8.GetBytes(input);
    byte[] iv = new byte[16]; 

    //Set up
    AesEngine engine = new AesEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
   //PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher); //Default scheme is PKCS5/PKCS7
   KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(keyStringBase64));
   ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16);

   // Encrypt
   cipher.Init(true, keyParamWithIV);
   byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
   int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
   cipher.DoFinal(outputBytes, length); //Do the final block
   return Convert.ToBase64String(outputBytes);
}

public static string BCDecrypt(string input)
{
    string keyString = "mysecretkey12345";
    string keyStringBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(keyString));
    byte[] inputBytes = Encoding.UTF8.GetBytes(input);
    byte[] iv = new byte[16];
    //Set up
    AesEngine engine = new AesEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher); //Default scheme is PKCS5/PKCS7
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(keyStringBase64));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16);

    //Decrypt            
    byte[] outputBytes = Convert.FromBase64String(input);
    cipher.Init(false, keyParamWithIV);
    byte[] comparisonBytes = new byte[cipher.GetOutputSize(outputBytes.Length)];
    int length = cipher.ProcessBytes(outputBytes, comparisonBytes, 0);
    cipher.DoFinal(comparisonBytes, length); //Do the final block
    return System.Text.Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length);
}
  

Это код php, который я использую:

 <?
    function encrypt($input, $key) {
        $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB); 
        $input = Security::pkcs5_pad($input, $size); 
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');  
        $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND); 
        mcrypt_generic_init($td, $key, $iv); 
        $data = mcrypt_generic($td, $input); 
        mcrypt_generic_deinit($td); 
        mcrypt_module_close($td); 
        $data = base64_encode($data); 
        return $data; 
   } 

   function pkcs5_pad ($text, $blocksize) { 
       $pad = $blocksize - (strlen($text) % $blocksize); 
       return $text . str_repeat(chr($pad), $pad); 
   }

   function decrypt($sStr, $sKey) {
       $decrypted= mcrypt_decrypt(
          MCRYPT_RIJNDAEL_128,
          $sKey, 
          base64_decode($sStr), 
          MCRYPT_MODE_ECB
       );
       $dec_s = strlen($decrypted); 
       $padding = ord($decrypted[$dec_s-1]); 
       $decrypted = substr($decrypted, 0, -$padding);
       return $decrypted;
   }

   echo "Input: " . $_REQUEST["inp"] . "<br>Decrypt: ". decrypt($_REQUEST["inp"], 'mysecretkey12345')."<br>";
   ?>
  

Когда я пытаюсь зашифровать короткую строку с помощью c #, такую как «greatscott», я получаю следующий результат: dSk7z0F4JYsc0zhl95 yMw ==

Затем это расшифровывает ok с использованием кода php.

Однако, когда я пытаюсь зашифровать более длинную строку с помощью кода c #, такого как «это очень длинная строка», я получаю следующий результат: xcL4arrFD8Fie73evfHjvUjNEmZrA9h6SmO0ZRE82Hw =

И это не расшифровывается. Если я попытаюсь зашифровать ту же строку «это очень длинная строка» с помощью функции шифрования php, я получу xcL4arrFD8Fie73evfHjva6yJyeUOrB8IudISDhQk24 =

Таким образом, первая половина зашифрованной строки такая же, а вторая половина — нет. Это заставляет меня думать, что у меня неверное заполнение или что-то в этом роде.

Любые советы будут оценены.

Спасибо

Комментарии:

1. Используйте openssl для шифрования и дешифрования в PHP.

2. Вы используете режим ECB в коде PHP и режим CBC в коде C #. Кроме того, вы используете IV со всеми нулями в функции шифрования C #, но произвольный IV в коде PHP. Вы также не отправляете IV ни в одном коде. Здесь вы много ошибаетесь.

3. Используйте режим CTR. Забудьте, что вы слышали о каком-либо другом режиме.

4. На ум придет @Ben GCM или любые другие аутентифицированные коды. Но вам придется держаться подальше от mcrypt (самой дерьмовой криптографической библиотеки), поскольку в ней нет шифрования в режиме GCM или CTR .

Ответ №1:

Спасибо за предложения, Люк и Джеймс.

Сейчас я использую openssl для шифрования и дешифрования на PHP, и я генерирую случайный IV и передаю его обратно и вперед между системами для дешифрования.

Это код, который я сейчас использую:

c#

 public static string BCEncrypt(string input, out string iv_base64)
{
    byte[] inputBytes = Encoding.UTF8.GetBytes(input);
    SecureRandom random = new SecureRandom();
    byte[] iv = new byte[16];
    random.NextBytes(iv);
    iv_base64 = Convert.ToBase64String(iv);
    string keyString = "mysecretkey12345";
    string keyStringBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(keyString));

    //Set up
    AesEngine engine = new AesEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(keyStringBase64));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16);

    // Encrypt
    cipher.Init(true, keyParamWithIV);
    byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
    int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
    cipher.DoFinal(outputBytes, length); //Do the final block
    return Convert.ToBase64String(outputBytes);
}

public static string BCDecrypt(string input, string iv_base64)
{
    string keyString = "mysecretkey12345";
    string keyStringBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(keyString));
    byte[] inputBytes = Encoding.UTF8.GetBytes(input);
    byte[] iv = Convert.FromBase64String(iv_base64);
    //Set up
    AesEngine engine = new AesEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(keyStringBase64));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16);

    //Decrypt            
    byte[] outputBytes = Convert.FromBase64String(input);
    cipher.Init(false, keyParamWithIV);
    byte[] comparisonBytes = new byte[cipher.GetOutputSize(outputBytes.Length)];
    int length = cipher.ProcessBytes(outputBytes, comparisonBytes, 0);
    cipher.DoFinal(comparisonBytes, length); //Do the final block
    return Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length);
}
  

Сторона PHP выглядит следующим образом:

 $iv = base64_decode($iv_base64);
$method = "aes-128-cbc";
$password = "mysecretkey12345";
$decrypted = openssl_decrypt($data, $method, $password,0, $iv);
  

И для генерации iv и шифрования строки в PHP я использую:

 $iv = openssl_random_pseudo_bytes(16)
$encrypted = openssl_encrypt("something interesting", $method, $password,0,$iv);
  

Итак, теперь я могу шифровать на C # или PHP и расшифровывать на C # или PHP.

Я передаю базовую 64-кодированную iv и зашифрованную строку между двумя системами, используя https.

Есть какие-либо комментарии по этому решению? (Безопасность или иначе?)