проблема шифрования данных с помощью C# на стороне сервера и шифрования их с помощью CryptoJS на стороне клиента

#c# #encryption #aes #cryptojs

Вопрос:

Я также немного запутался в различиях между C# и CryptoJS.у меня есть две серверные функции для шифрования данных с помощью AES256 бит следующим образом;

 public string EncryptText_PBKDF2(string input, string password)
    {           
        // Get the bytes of the strings         
        byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        // Hash the password with SHA256 for AES key
        passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
        byte[] bytesEncrypted = AES_Encrypt_PBKDF2(bytesToBeEncrypted, passwordBytes);
        string result = Convert.ToBase64String(bytesEncrypted);
        return resu<
    }

private byte[] AES_Encrypt_PBKDF2(byte[] bytesToBeEncrypted, byte[] passwordBytes)
    {
        byte[] encryptedBytes = null;
        
        byte[] saltBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
        
        using (MemoryStream ms = new MemoryStream())
        {
            aes.KeySize = 256;
            aes.BlockSize = 128;
            aes.IV = MD5.Create().ComputeHash(passwordBytes);//16 byte
            
            var PBKDF2_key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            aes.Key = PBKDF2_key.GetBytes(aes.KeySize / 8);//32 byte
            aes.Mode = CipherMode.CBC;
            using (var cs = new CryptoStream(ms, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                cs.Close();
            }
            encryptedBytes = ms.ToArray();
        }
        return encryptedBytes;
    }
 

затем я отправляю его на просмотр с помощью действия контроллера;

 string res = aesIsl.EncryptText_PBKDF2("my text", "my key");
ViewBag.Crypted1 = res;
 

на стороне клиента я получаю его из скрытого поля

 <div id="crypted"><input id="hidden1" data-enc="@ViewBag.Crypted1" type="hidden" /></div>
 

и расшифруйте его с помощью библиотеки crypto-js(у меня есть 4 попытки, указанные поверх них)

вот моя функция расшифровки и попытки:

 function AesleDesifrele_PBKDF2(ciphertext, pwd) {    
    var salt = "0000000000000000";
    var iv = CryptoJS.MD5(CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pwd)));          
    //these are my attempts to decrypt
    //ATTEMPT #1:
    //returning object contains a word array but converting it to utf8 string
    //causes "Malformed UTF-8 data" error
    console.log(CryptoJS.AES.decrypt(ciphertext, pwd).toString(CryptoJS.enc.Utf8));
    //ATTEMPT #2
    var key = CryptoJS.PBKDF2(
        CryptoJS.enc.Utf8.parse(pwd).toString(CryptoJS.enc.Utf8),
        CryptoJS.enc.Hex.parse(salt),
        { keySize: 128 / 32, iterations: 1000 }
    );
    var decrypted = CryptoJS.AES.decrypt(
        ciphertext,
        key,
        { iv: iv }
    );
    //returning object contains a word array but converting it to utf8 string
    //causes "Malformed UTF-8 data" error
    console.log(decrypted.toString(CryptoJS.enc.Utf8));
    //ATTEMPT #3
    var raw = base64UrlDecode(ciphertext);
    var iv1 = CryptoJS.lib.WordArray.create(CryptoJS.MD5(CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pwd))));;
    var salt1 = CryptoJS.lib.WordArray.create(CryptoJS.enc.Hex.parse(salt));
    var key1 = generateKey(pwd, salt1);
    var ciphertextWords = CryptoJS.lib.WordArray.create(raw.words.slice(128 / 32   128 / 32));
    var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: ciphertextWords });
    var plaintextArray = CryptoJS.AES.decrypt(
        cipherParams,
        key1,
        { iv: iv1 }
    );
    console.log(CryptoJS.enc.Utf8.stringify(plaintextArray)); 
    //returning object contains a word array but converting it to utf8 string
    //returns nothing
    //ATTEMPT #4
    var iv2 = CryptoJS.MD5(CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pwd)));
    var Pass = CryptoJS.enc.Utf8.parse(pwd);
    var Salt = CryptoJS.enc.Utf8.parse(salt);
    var key256Bits1000Iterations = CryptoJS.PBKDF2(Pass.toString(CryptoJS.enc.Utf8), Salt, { keySize: 256 / 32, iterations: 1000 });
    var cipherParams = CryptoJS.lib.CipherParams.create({
        ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
    });
    var decrypted = CryptoJS.AES.decrypt(cipherParams, key256Bits1000Iterations, { mode: CryptoJS.mode.CBC, iv: iv2, padding: CryptoJS.pad.Pkcs7 });
    console.log(decrypted.toString(CryptoJS.enc.Utf8));
    //returning object contains a word array but converting it to utf8 string
    //returns nothing
}
 

это функция для генерации ключа для расшифровки CryptoJS

 function generateKey(secret, salt) {
return CryptoJS.PBKDF2(
    secret,
    salt,
    {
        keySize: this.keySize / 32, // size in Words
        iterations: 1000,
        hasher: CryptoJS.algo.SHA256
    }
);
 

}

это функция преобразования, которую я использую

 function base64UrlDecode(str) {
    return CryptoJS.enc.Base64.parse(str.replace(/-/g, ' ').replace(/_/g, '/'));
}
 

несмотря на то,что я контролирую параметры на клиенте(зашифрованный текст,пароль,IV и соль) точно так же, как и на сервере, CryptoJS.decrypt ничего не возвращает без каких-либо ошибок.я думаю, мне не хватает преобразования чего-либо в другое, чтобы C# был совместим с CryptoJS.

любые советы приветствуются.

заранее спасибо.

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

1. Если у вас нет особых требований использовать эти алгоритмы именно таким образом и никак иначе, я бы рекомендовал libsodium-он имеет привязки C# и JS и гораздо более простой интерфейс.

2. Для меня это слишком похоже на случайную попытку. Первое, что бросается в глаза,-это то, что вы, похоже, только предварительно хэшируете пароль (а не только IV) в C#, используя SHA-256. Тем не менее, я бы поддержал комментарий Йеруна (Хой Йерун) о том, что изобретать свою собственную схему было бы очень плохой идеей, потому что я бы полностью разрушил ее за считанные секунды, даже если вы используете AES. Кстати, способ отладки крипто кода состоит в том, чтобы распечатать все промежуточные значения (IV ключа и т. Д.) В шестнадцатеричных числах, а затем искать различия между приложениями. Ваш код с обеих сторон должен быть СИММЕТРИЧНЫМ, как и шифр

3. спасибо, Джерун. я проверю это.также спасибо тебе, Мартен, за твою comment.as вы заметили, что я хэшировал pwd в C#, используя sha-256, чтобы подготовить его к использованию AES256.также я хэшировал этот хэшированный pwd в c#, используя md5, потому что я использую один и тот же pwd(совместно используемый с обменом ключами диффи-Хеллмана), и я хэшировал его с помощью md5, чтобы использовать его в качестве IV на стороне JS.я зарегистрировал значения обеих сторон путем их хэширования. все значения одинаковы.я думаю,что мне нужно выполнить некоторое преобразование для библиотеки crypto-js, но я не смог найти, какое из них и как.большое вам спасибо за ваше время.