Зашифровать RijndaelManaged 128 в unity c# и расшифровать в Node.JS

Я ищу способ зашифровать массив байтов в единстве С# и расшифровать на сервере node.js.

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

TypeError: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

При расшифровке файла, зашифрованного в единстве, с помощью RijndaelManaged 128

Найдите код шифрования и дешифрования ниже:

Шифрование Unity C#

private void GenerateEncryptionKey(string userID)
{
    //Generate the Salt, with any custom logic and using the user's ID
    StringBuilder salt = new StringBuilder();
    for (int i = 0; i < 8; i++)
    {
        salt.Append("," + userID.Length.ToString());
    }

    Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes (Encoding.UTF8.GetBytes(userID), Encoding.UTF8.GetBytes(salt.ToString()), 100);
    m_cryptoKey = pwdGen.GetBytes(KEY_SIZE / 8);
    m_cryptoIV = pwdGen.GetBytes(KEY_SIZE / 8);
}

public void Save(string path)
{
    string json = MiniJSON.Json.Serialize(m_saveData);

    using (RijndaelManaged crypto = new RijndaelManaged())
    {
        crypto.BlockSize = KEY_SIZE;
        crypto.Padding = PaddingMode.PKCS7;
        crypto.Key = m_cryptoKey;
        crypto.IV = m_cryptoIV;
        crypto.Mode = CipherMode.CBC;

        ICryptoTransform encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);

        byte[] compressed = null;

        using (MemoryStream compMemStream = new MemoryStream())
        {
            using (StreamWriter writer = new StreamWriter(compMemStream, Encoding.UTF8))
            {
                writer.Write(json);
                writer.Close();

                compressed = compMemStream.ToArray();
            }
        }

        if (compressed != null)
        {
            using (MemoryStream encMemStream = new MemoryStream(compressed))
            {
                using (CryptoStream cryptoStream = new CryptoStream(encMemStream, encryptor, CryptoStreamMode.Write))
                {
                    using (FileStream fs = File.Create(GetSavePath(path)))
                    {
                        byte[] encrypted = encMemStream.ToArray();

                        fs.Write(encrypted, 0, encrypted.Length);
                        fs.Close();
                    }
                }
            }
        }
    }
}

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

Расшифровка Node.JS

var sUserID = "hello-me";
var sSalt = "";

for (var i = 0; i < 8; i++)
{
    sSalt += "," + sUserID.length;
}

var KEY_SIZE = 128;

crypto.pbkdf2(sUserID, sSalt, 100, KEY_SIZE / 4, function(cErr, cBuffer){
    var cKey = cBuffer.slice(0, cBuffer.length / 2);
    var cIV = cBuffer.slice(cBuffer.length / 2, cBuffer.length);

    fs.readFile("save.sav", function (cErr, cData){
        try
        {
            var cDecipher = crypto.createDecipheriv("AES-128-CBC", cKey, cIV);

            var sDecoded = cDecipher.update(cData, null, "utf8");
            sDecoded += cDecipher.final("utf8");
            console.log(sDecoded);
        }
        catch(e)
        {
            console.log(e.message);
            console.log(e.stack);
        }
    });
});

Я считаю, что проблема как-то связана с прокладкой! Я не использую:

cryptoStream.FlushFinalBlock();

при сохранении файла в земле С#, потому что по какой-то причине после этого С# больше не может его расшифровать, и это также не влияет на способность узла расшифровать его, но, может быть, я просто что-то упустил в расшифровка его с дополнением?

Любая помощь приветствуется


person Tristan    schedule 13.08.2014    source источник
comment
вы смотрели на этот вопрос? здесь   -  person Rudolfwm    schedule 13.08.2014
comment
@Rudolfwm Я видел это, но, к сожалению, я уже внес предложенные изменения, и все равно не повезло, все равно спасибо   -  person Tristan    schedule 14.08.2014
comment
Я видел, как вы это исправили, я также заметил: byte[] encrypted = encMemStream.ToArray(); читает не из того потока. Должно быть byte[] encrypted = cryptoStream .ToArray();   -  person Rudolfwm    schedule 14.08.2014


Ответы (2)


Одна из проблем заключается в том, что вы используете PasswordDeriveBytes, который согласно этой статье для PBKDF1, тогда как Rfc2898DeriveBytes для PBKDF2. Вы используете PBKDF2 в своем скрипте узла.

Затем вы должны проверить, что ваши значения cKey и cIV совпадают между C# и node.

person mscdex    schedule 13.08.2014
comment
Привет, mscdex, спасибо за ответ, я ранее пробовал Rfc2898DeriveBytes, но вы правы, я должен использовать это, и это ошибка в моем примере. Оба моих значения ключа и iv одинаковы между С# и узлом. Я считаю, что это как-то связано с прокладкой, но безуспешно пробовал несколько вещей. - person Tristan; 14.08.2014

Хорошо, кажется, что порядок операций очень важен при шифровании и дешифровании с использованием RijndaelManaged.

Ниже приведен код для шифрования и дешифрования в Unity, который работает с кодом node.js, опубликованным в вопросе.

public void Save(string path)
{
    string json = MiniJSON.Json.Serialize(m_saveData);

    using (RijndaelManaged crypto = new RijndaelManaged())
    {
        crypto.BlockSize = KEY_SIZE;
        crypto.Padding = PaddingMode.PKCS7;
        crypto.Key = m_cryptoKey;
        crypto.IV = m_cryptoIV;
        crypto.Mode = CipherMode.CBC;

        ICryptoTransform encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);

        byte[] compressed = null;

        using (MemoryStream compMemStream = new MemoryStream())
        {
            using (StreamWriter writer = new StreamWriter(compMemStream, Encoding.UTF8))
            {
                writer.Write(json);
                writer.Close();

                //compressed = CLZF2.Compress(compMemStream.ToArray());
                compressed = compMemStream.ToArray();
            }
        }

        if (compressed != null)
        {
            using (MemoryStream encMemStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(encMemStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(compressed, 0, compressed.Length);
                    cryptoStream.FlushFinalBlock();

                    using (FileStream fs = File.Create(GetSavePath(path)))
                    {
                        encMemStream.WriteTo(fs);
                    }
                }
            }
        }
    }
}

public void Load(string path)
{
    path = GetSavePath(path);

    try
    {
        byte[] decrypted = null;

        using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            using (RijndaelManaged crypto = new RijndaelManaged())
            {
                crypto.BlockSize = KEY_SIZE;
                crypto.Padding = PaddingMode.PKCS7;
                crypto.Key = m_cryptoKey;
                crypto.IV = m_cryptoIV;
                crypto.Mode = CipherMode.CBC;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);

                using (CryptoStream cryptoStream = new CryptoStream(fs, decryptor, CryptoStreamMode.Read))
                {
                    using (MemoryStream decMemStream = new MemoryStream())
                    {
                        var buffer = new byte[512];
                        var bytesRead = 0;

                        while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            decMemStream.Write(buffer, 0, bytesRead);
                        }

                        //decrypted = CLZF2.Decompress(decMemStream.ToArray());
                        decrypted = decMemStream.ToArray();
                    }
                }
            }
        }

        if (decrypted != null)
        {
            using (MemoryStream jsonMemoryStream = new MemoryStream(decrypted))
            {
                using (StreamReader reader = new StreamReader(jsonMemoryStream))
                {
                    string json = reader.ReadToEnd();

                    Dictionary<string, object> saveData = MiniJSON.Json.Deserialize(json) as Dictionary<string, object>;

                    if (saveData != null)
                    {
                        m_saveData = saveData;
                    }
                    else
                    {
                        Debug.LogWarning("Trying to load invalid JSON file at path: " + path);
                    }
                }
            }
        }
    }
    catch (FileNotFoundException e)
    {
        Debug.LogWarning("No save file found at path: " + path);
    }
}
person Tristan    schedule 14.08.2014