Próbuję nauczyć się bezpieczeństwa cybernetycznego i to jest pierwsza rzecz, którą zrobiłem na nim. Używam tego dokumentu MSDN (https://docs.Microsoft.com/en-us/dotnet/api/system.security.cryptography.RFC2898.Cryptography?rediredFrom=msdn& ;view=netcore-3.1) i to częściowo działa . Zakładam, że szyfruje go w porządku, jeśli chodzi o deszyfrujące, niektóre z oryginalnych danych jest tam, ale niektórzy zostaną utracone. Dane, które są zaszyfrowane, jest klasą, która została sformatowana w strumieniu JSON (nie sądzę, że jest to istotne, ponieważ nadal jest szyfrowany ciągiem). Dane oryginalne

Ale gdy zostanie zaszyfrowany i odszyfrowany, okazuje się tak: Zaszyfrowane Następnie deszyfrowane dane

Przeprowadziłem ten kod i porównałem wyniki 5+ razy i zawsze: Start jest nieprawidłowy, nazwa użytkownika jest częściowo dobra, hasło jest zawsze w porządku, a loginkey jest częściowo odpowiedni. Więc błąd powraca i zawsze w tym samym miejscu.

Informacje powinieneś wiedzieć, zaszyfrowane i zapisane w pliku .txt. Program uruchomi się ponownie i spróbuje go odszyfrował. Sól i hasło są zapisywane w innym pliku, a te są czytane i używane w deszyfrowaniu.

Występuje podobne pytanie na stackoverflow, ale odpowiedź mówi, aby użyć Rijndaela (tak naprawdę nie jest odpowiedzią), ten kod jest dla mnie uczenia się i chcesz odpowiedź, która nie jest 4 liniami.

Kod, jeśli jest ciekawy (ale jest zasadniczo taki sam jak dokument MSDN):

Szyfrowanie:

    static void EncryptFile()
    {
        string pwd1 = SteamID;//steamID is referring to account ID on Valve Steam           
        using (RNGCryptoServiceProvider rngCsp = new
        RNGCryptoServiceProvider())
        {
            rngCsp.GetBytes(salt1); //salt1 is a programme variable and will get saved to a file
        }
        SecureData File = new SecureData(_UserName,_PassWord,_LoginKey);
        string JsonFile = JsonConvert.SerializeObject(File); //puts the class into Json format
        int myIterations = 1000; //not needed
        try
        {
            Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,
            myIterations);
            Aes encAlg = Aes.Create(); // This might be the issue as AES will be different when you decrypt 
            encAlg.Key = k1.GetBytes(16);
            MemoryStream encryptionStream = new MemoryStream();
            CryptoStream encrypt = new CryptoStream(encryptionStream,
            encAlg.CreateEncryptor(), CryptoStreamMode.Write);
            byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(
            JsonFile); //encrypt Data 

            encrypt.Write(utfD1, 0, utfD1.Length);
            encrypt.FlushFinalBlock();
            encrypt.Close();
            byte[] edata1 = encryptionStream.ToArray();
            k1.Reset();

            System.IO.File.WriteAllBytes(SecureFile, edata1); //writes encrypted data to file
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: ", e);
        }
    }

Deszyfrowanie:

    static void DecryptFile()
    {
        string pwd1 = SteamID;
        byte[] edata1;
        try
        {
            edata1 = System.IO.File.ReadAllBytes(SecureFile); //reads the file with encrypted data on it
            Aes encAlg = Aes.Create(); //I think this is the problem as the keyvalue changes when you create a new programme
            Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1); //inputs from last time carry over
            Aes decAlg = Aes.Create();
            decAlg.Key = k2.GetBytes(16);
            decAlg.IV = encAlg.IV;
            MemoryStream decryptionStreamBacking = new MemoryStream();
            CryptoStream decrypt = new CryptoStream(
            decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
            decrypt.Write(edata1, 0, edata1.Length);
            decrypt.Flush();
            decrypt.Close();
            k2.Reset();
            string data2 = new UTF8Encoding(false).GetString(
            decryptionStreamBacking.ToArray());//decrypted data  
            SecureData items = JsonConvert.DeserializeObject<SecureData>(data2); //reformat it out of JSon(Crashes as format isn't accepted)
            _UserName = items.S_UserName;
            _PassWord = items.S_Password;
            _LoginKey = items.S_LoginKey;
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: ", e);
            NewLogin();
        }
    }

Klasa struktura:

    class SecureData
    {
        public string S_UserName { get; set; } //These are variables that are apart of Valve steam Login process 
        public string S_Password { get; set; }
        public string S_LoginKey { get; set; }

        public SecureData(string z, string x, string y)
        {
            S_UserName = z;
            S_Password = x;
            S_LoginKey = y;
        }
    }
1
Andrew Foot 31 lipiec 2020, 02:40

1 odpowiedź

Najlepsza odpowiedź

Problem jest spowodowany różnymi IVS do szyfrowania i deszyfrowania. W celu uzyskania udanego deszyfrowania IV z szyfrowania należy użyć.

Dlaczego stosowane są różne IVS? Gdy powstaje instancja AES, losowy IV jest niejawnie generowany. Dwukrotnie instancje różnych {X1} oznacza dwa różne IVS. W zaksięgowanym kodzie, instancje instancji AES są używane do szyfrowania i odszyfrowania. Chociaż odniesienie encAlg używane w odszyfrowaniu ma taką samą nazwę, jak w przypadku szyfrowania, instancja odwoływana jest inna (a mianowicie instancji nowo utworzone podczas deszyfrowania). Jest to inne w przykładzie Microsoft. Tam IV szyfrowania jest używany w odszyfrowaniu: decAlg.IV = encAlg.IV, gdzie encAlg jest instancją AES, z którą wykonano szyfrowanie.

Rozwiązaniem jest przechowywanie IV z szyfrowania w pliku, dzięki czemu można go użyć w deszyfrowaniu. IV nie jest tajemnicą i zwykle jest umieszczony przed CipHertekstem:

Niezbędne zmiany w EncryptFile:

...
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(JsonFile); 

encryptionStream.Write(encAlg.IV, 0, encAlg.IV.Length);           // Write the IV
encryptionStream.Flush();
            
encrypt.Write(utfD1, 0, utfD1.Length);
...
            

Niezbędne zmiany w DecryptFile:

...
edata1 = System.IO.File.ReadAllBytes(SecureFile); 
            
byte[] iv = new byte[16];                                         // Separate IV and ciphertext
byte[] ciphertext = new byte[edata1.Length - iv.Length];
Array.Copy(edata1, 0, iv, 0, iv.Length);
Array.Copy(edata1, iv.Length, ciphertext, 0, ciphertext.Length);
...     
Aes encAlg = Aes.Create();                                        // Remove this line
...
decAlg.IV = iv;                                                   // Use the separated IV
...
decrypt.Write(ciphertext, 0, ciphertext.Length);                  // Use the separated ciphertext

Kilka uwag:

  • Dla każdego szyfrowania należy wytworzyć nową, losową sól i połączyć się z cyperektyką analogową do IV. Podczas odszyfrowania sól można następnie określić analogicznie do IV. Rozważmy dodatkowo RFC8018, SEC 4.1.
  • Liczba iteracji spowalnia wyprowadzenie klucza, który powinien dokonać ataku przez powtarzające się próby trudniejsze. Dlatego wartość powinna być tak duża, jak to możliwe. Rozważmy dodatkowo RFC8018, SEC 4.2.
  • Dane uwierzytelniające (tj. Hasła) nie są szyfrowane, ale hashed, Tutaj.
2
Topaco 31 lipiec 2020, 18:19