Плохая ошибка заполнения PKCS7: недопустимая длина 106

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

Если я устанавливаю PaddingMode в None, он возвращает некоторые альфа-символы и случайные символы в журнале.

Возможно, я что-то упускаю из установки правильной структуры, которая выглядит следующим образом:

  • Шифр Rijndael (AES)
  • Размер блока 128 бит (16 байт)
  • Ключ режима CBC (Cipher Block Chaining)
  • Хэш-пароль MD5
  • IV То же, что ключ
  • Кодировка данных Base64 символов
  • Кодировка UTF-8

Будем очень благодарны за любую помощь в исправлении этой ошибки и любую помощь в обеспечении соблюдения вышеуказанной структуры! Спасибо

Ошибка

CryptographicException: Bad PKCS7 padding. Invalid length 106.
Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding, Int32 length, Int32 position) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs:363)
Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs:515)
Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs:554)
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Security.Cryptography/RijndaelManagedTransform.cs:94)
APIConnector.Decrypt (System.String toDecrypt) (at Assets/APIConnector.cs:85)

Мой код

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using System.IO;

public class APIConnector : MonoBehaviour {

    // Use this for initialization
    void Start () {

        Debug.Log ("Starting API connector");


    }

    // Update is called once per frame
    void Update () {



    }

    static string data;
    string firstName="";
    string password="";

    void OnGUI() {

        firstName = GUILayout.TextField (firstName, GUILayout.Width(300));
        password = GUILayout.TextField (password, GUILayout.Width(300));

        if (GUILayout.Button ("Submit"))
                        submit ();

    }

    //Our functions

    void submit(){

        Debug.Log ("Name is: " + firstName + " encrypted is: " + Encrypt(firstName));
        Debug.Log ("Name is: " + firstName + " decrypted is: " + Decrypt(firstName));

    }


            public static string Encrypt (string toEncrypt)
            {
        byte[] keyArray = UTF8Encoding.UTF8.GetBytes ("SecretPassphrase");
                // 256-AES key
        int numBytes = System.Text.Encoding.UTF8.GetBytes(toEncrypt).Length;
        Debug.Log ("Bytes: " + numBytes);
                byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes (toEncrypt);
                RijndaelManaged rDel = new RijndaelManaged ();
                rDel.Key = keyArray;
                rDel.BlockSize = 128;
                rDel.Mode = CipherMode.CBC;
                // http://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx
                rDel.Padding = PaddingMode.PKCS7;
                // better lang support
                ICryptoTransform cTransform = rDel.CreateEncryptor ();
                byte[] resultArray = cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);
                return Convert.ToBase64String (resultArray, 0, resultArray.Length);
            }

            public static string Decrypt (string toDecrypt)
            {
        byte[] keyArray = UTF8Encoding.UTF8.GetBytes ("SecretPassphrase");
                // AES-256 key
        byte[] encryptedData = System.Convert.FromBase64String(toDecrypt);
                //byte[] toEncryptArray = Convert.FromBase64String (toDecrypt);
                RijndaelManaged rDel = new RijndaelManaged ();
                rDel.Key = keyArray;
                rDel.BlockSize = 128;
                rDel.Mode = CipherMode.CBC;
                rDel.IV = rDel.Key;
                // http://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx
                rDel.Padding = PaddingMode.PKCS7;
                // better lang support
                ICryptoTransform cTransform = rDel.CreateDecryptor ();
        byte[] resultArray = cTransform.TransformFinalBlock (encryptedData, 0, encryptedData.Length);
                return UTF8Encoding.UTF8.GetString (resultArray);
            }


}

person DT.DTDG    schedule 23.05.2014    source источник


Ответы (1)


Похоже, что вы не устанавливаете IV при шифровании, поэтому автоматически будет использоваться случайный IV. Поскольку вы устанавливаете IV при расшифровке (и он не будет таким же, как при шифровании), первый выходной блок будет поврежден. Если сообщение достаточно короткое (‹ 1 блока), то заполнение также будет повреждено, что может привести к этой ошибке.

Как обычно, я отмечу, что среди других возможных проблем использование того же IV в качестве ключа является плохой практикой, как и использование Encoding.UTF8.GetBytes() для вывода ключа.

person Iridium    schedule 23.05.2014
comment
Спасибо за ваш ответ. Я новичок в С# и даже новее в шифровании С#. Можете ли вы отредактировать свой ответ, чтобы привести пример исправления? Спасибо! - person DT.DTDG; 25.05.2014
comment
@DT.DTDG - вам просто нужно добавить строку: rDel.IV = rDel.Key; в ваш метод Encrypt в том же месте, что и в ваш метод Decrypt. - person Iridium; 25.05.2014
comment
Спасибо, очень признателен! Принял ответ. Вы также упомянули лучшую практику, чем использование «Encoding.UTF8.GetBytes ()»? Не стесняйтесь взвешиваться. - person DT.DTDG; 25.05.2014
comment
@ DT.DTDG - это, вероятно, лучше всего задать как отдельный вопрос, хотя, вероятно, на SO есть ряд вопросов, на которые уже есть ответы на эту тему. Я предлагаю изучить PBKDF2 в отношении создания ключа из пароля, и мой ответ здесь: stackoverflow.com/questions/8041451/ в отношении правильного использования IV. - person Iridium; 25.05.2014
comment
Спасибо @Iridum за подробный комментарий. Ваше здоровье - person DT.DTDG; 25.05.2014