Proste niepewne dwukierunkowe „zaciemnianie” danych?


426

Szukam bardzo prostego zaciemnienia (takiego jak szyfrowanie i deszyfrowanie, ale niekoniecznie bezpieczne) dla niektórych danych. To nie jest krytyczne zadanie. Potrzebuję czegoś, aby uczciwi ludzie byli uczciwi, ale coś nieco silniejszego niż ROT13 lub Base64 .

Wolałbym coś, co jest już zawarte w .NET Framework 2.0, więc nie muszę się martwić o zewnętrzne zależności.

Naprawdę nie chcę się bawić z kluczami publicznymi / prywatnymi itp. Nie wiem dużo o szyfrowaniu, ale wiem wystarczająco dużo, aby wiedzieć, że wszystko, co napisałem, byłoby mniej niż bezwartościowe ... Prawdopodobnie spieprzyłbym matematykę i uczyniłbym ją trywialną.


3
Cześć Mark - nie ma problemu. Czułem się źle, że musiałem nie zaakceptować odpowiedzi Richdiet, ponieważ faktycznie skorzystałem z jego rozwiązania i zadziałało dobrze. Jednak ciągle tu wracałem, żeby przeczytać inne odpowiedzi, a twoje naprawdę jest lepsze. Nie ma powodu, aby mówić ludziom, aby korzystali z czegoś, co, chociaż działa, nie jest tak naprawdę świetnym sposobem na zrobienie czegoś, gdy dostępna jest lepsza odpowiedź.
Matt Dawdy,

3
Zaoszczędź sobie godzin i użyj HttpServerUtility.UrlTokenEn / Decode, aby przekonwertować tam iz powrotem z tablic bajtów na ciąg przyjazny dla adresu URL.
Praesagus

32
+1 za to, że nie próbujesz wykonać własnego sprytnego projektu. Być może nie wiesz zbyt wiele o szyfrowaniu, ale fakt, że wiesz, że stawia cię o wiele lat przed większością programistów, których spotkałem, którzy nie wiedzą dużo o szyfrowaniu, ale myślą, że i tak mogą stworzyć własne rozwiązanie.
Dinah

6
Uwaga: Wiele odpowiedzi w tym pytaniu dotyczy tylko nieuwierzytelnionego szyfrowania. Oznacza to, że osoba atakująca może zmienić dane bez powiadomienia aplikacji . Prowadzi to również do innych poważnych luk w zabezpieczeniach (takich jak deszyfrowanie bez klucza z powodu wypełniania wyroczni). TL; DR: Nie używaj kodu w podanych odpowiedziach, jeśli nie zgadzasz się z tym lub nie rozumiesz, co właśnie powiedziałem.
usr

36
Żadna odpowiedź na to pytanie nie opisuje bezpiecznego szyfrowania. Zamiast tego użyj odpowiedzi jbtule z Szyfruj i odszyfruj ciąg .
CodesInChaos

Odpowiedzi:


471

Inne odpowiedzi tutaj działają dobrze, ale AES to bardziej bezpieczny i aktualny algorytm szyfrowania. Jest to klasa, którą uzyskałem kilka lat temu, aby wykonać szyfrowanie AES, które z czasem zmodyfikowałem, aby były bardziej przyjazne dla aplikacji internetowych (np. Zbudowałem metody szyfrowania / deszyfrowania, które działają z ciągiem przyjaznym adresowi URL). Ma również metody, które działają z tablicami bajtów.

UWAGA: należy użyć różnych wartości w tablicach Key (32 bajty) i Vector (16 bajtów)! Nie chciałbyś, aby ktoś odkrył twoje klucze, zakładając, że użyłeś tego kodu w obecnej postaci! Wszystko, co musisz zrobić, to zmienić niektóre liczby (muszą być <= 255) w tablicach Key i Vector (zostawiłem jedną niepoprawną wartość w tablicy Vector, aby mieć pewność, że to zrobisz ...). Możesz użyć https://www.random.org/bytes/, aby łatwo wygenerować nowy zestaw:

Korzystanie z niego jest proste: wystarczy utworzyć instancję klasy, a następnie wywołać (zwykle) EncryptToString (ciąg StringToEncrypt) i DecryptString (ciąg StringToDecrypt) jako metody. Po tym, jak ta klasa będzie na miejscu, nie może być łatwiej (ani bezpieczniej).


using System;
using System.Data;
using System.Security.Cryptography;
using System.IO;


public class SimpleAES
{
    // Change these keys
    private byte[] Key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 });

    // a hardcoded IV should not be used for production AES-CBC code
    // IVs should be unpredictable per ciphertext
    private byte[] Vector = __Replace_Me__({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 2521, 112, 79, 32, 114, 156 });


    private ICryptoTransform EncryptorTransform, DecryptorTransform;
    private System.Text.UTF8Encoding UTFEncoder;

    public SimpleAES()
    {
        //This is our encryption method
        RijndaelManaged rm = new RijndaelManaged();

        //Create an encryptor and a decryptor using our encryption method, key, and vector.
        EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector);
        DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector);

        //Used to translate bytes to text and vice versa
        UTFEncoder = new System.Text.UTF8Encoding();
    }

    /// -------------- Two Utility Methods (not used but may be useful) -----------
    /// Generates an encryption key.
    static public byte[] GenerateEncryptionKey()
    {
        //Generate a Key.
        RijndaelManaged rm = new RijndaelManaged();
        rm.GenerateKey();
        return rm.Key;
    }

    /// Generates a unique encryption vector
    static public byte[] GenerateEncryptionVector()
    {
        //Generate a Vector
        RijndaelManaged rm = new RijndaelManaged();
        rm.GenerateIV();
        return rm.IV;
    }


    /// ----------- The commonly used methods ------------------------------    
    /// Encrypt some text and return a string suitable for passing in a URL.
    public string EncryptToString(string TextValue)
    {
        return ByteArrToString(Encrypt(TextValue));
    }

    /// Encrypt some text and return an encrypted byte array.
    public byte[] Encrypt(string TextValue)
    {
        //Translates our text value into a byte array.
        Byte[] bytes = UTFEncoder.GetBytes(TextValue);

        //Used to stream the data in and out of the CryptoStream.
        MemoryStream memoryStream = new MemoryStream();

        /*
         * We will have to write the unencrypted bytes to the stream,
         * then read the encrypted result back from the stream.
         */
        #region Write the decrypted value to the encryption stream
        CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        #endregion

        #region Read encrypted value back out of the stream
        memoryStream.Position = 0;
        byte[] encrypted = new byte[memoryStream.Length];
        memoryStream.Read(encrypted, 0, encrypted.Length);
        #endregion

        //Clean up.
        cs.Close();
        memoryStream.Close();

        return encrypted;
    }

    /// The other side: Decryption methods
    public string DecryptString(string EncryptedString)
    {
        return Decrypt(StrToByteArray(EncryptedString));
    }

    /// Decryption when working with byte arrays.    
    public string Decrypt(byte[] EncryptedValue)
    {
        #region Write the encrypted value to the decryption stream
        MemoryStream encryptedStream = new MemoryStream();
        CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
        decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
        decryptStream.FlushFinalBlock();
        #endregion

        #region Read the decrypted value from the stream.
        encryptedStream.Position = 0;
        Byte[] decryptedBytes = new Byte[encryptedStream.Length];
        encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
        encryptedStream.Close();
        #endregion
        return UTFEncoder.GetString(decryptedBytes);
    }

    /// Convert a string to a byte array.  NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
    //      System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    //      return encoding.GetBytes(str);
    // However, this results in character values that cannot be passed in a URL.  So, instead, I just
    // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
    public byte[] StrToByteArray(string str)
    {
        if (str.Length == 0)
            throw new Exception("Invalid string value in StrToByteArray");

        byte val;
        byte[] byteArr = new byte[str.Length / 3];
        int i = 0;
        int j = 0;
        do
        {
            val = byte.Parse(str.Substring(i, 3));
            byteArr[j++] = val;
            i += 3;
        }
        while (i < str.Length);
        return byteArr;
    }

    // Same comment as above.  Normally the conversion would use an ASCII encoding in the other direction:
    //      System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    //      return enc.GetString(byteArr);    
    public string ByteArrToString(byte[] byteArr)
    {
        byte val;
        string tempStr = "";
        for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
        {
            val = byteArr[i];
            if (val < (byte)10)
                tempStr += "00" + val.ToString();
            else if (val < (byte)100)
                tempStr += "0" + val.ToString();
            else
                tempStr += val.ToString();
        }
        return tempStr;
    }
}

53
@AndyMcKenna - Odbywa się to celowo, aby zmienić wartości w tablicach, jak zauważa Mark w drugim akapicie.
Pauk,

42
Nie powinieneś używać IV w ten sposób. Dla danych dwóch wiadomości nie powinny być szyfrowane tym samym kluczem i tym samym kodem IV. IV powinien być losowy dla każdej wiadomości, dołączony do strumienia szyfrowania i odczytany przed odszyfrowaniem. crypto.stackexchange.com/a/82/1934
jbtule

30
Użycie losowego IV dla każdej wiadomości nie jest egzotyczne ani nowe, jest po prostu ważne i jest częścią konstrukcji algorytmu. Używanie przewidywalnej IV dla każdej wiadomości jest częstym błędem kryptograficznym, który nie musi być utrwalany.
jbtule

14
Zauważ także, że konsekwencją użycia CBC jako jego trybu jest to, że prawdopodobnie będziesz podatny na ataki typu padding oracle . Używaj uwierzytelnionego szyfrowania, a jeśli to możliwe, nie implementuj kryptografii samodzielnie .
Stephen Touset

57
Ostrzeżenie o bezpieczeństwie: nie używaj tego kodu Mimo że odpowiedź jest akceptowana, w powyższych komentarzach wspomniano o poważnych problemach z bezpieczeństwem, które autor ignorował przez 8 lat.
jbtule

176

Wyczyściłem SimpleAES (powyżej) na własny użytek. Naprawiono skomplikowane metody szyfrowania / deszyfrowania; oddzielne metody kodowania buforów bajtów, ciągów i ciągów przyjaznych adresom URL; wykorzystał istniejące biblioteki do kodowania adresów URL.

Kod jest mały, prostszy, szybszy, a wynik jest bardziej zwięzły. Na przykład johnsmith@gmail.comprodukuje:

SimpleAES: "096114178117140150104121138042115022037019164188092040214235183167012211175176167001017163166152"
SimplerAES: "YHKydYyWaHmKKnMWJROkvFwo1uu3pwzTr7CnARGjppg%3d"

Kod:

public class SimplerAES
{
    private static byte[] key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 });

    // a hardcoded IV should not be used for production AES-CBC code
    // IVs should be unpredictable per ciphertext
    private static byte[] vector = __Replace_Me_({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 });

    private ICryptoTransform encryptor, decryptor;
    private UTF8Encoding encoder;

    public SimplerAES()
    {
        RijndaelManaged rm = new RijndaelManaged();
        encryptor = rm.CreateEncryptor(key, vector);
        decryptor = rm.CreateDecryptor(key, vector);
        encoder = new UTF8Encoding();
    }

    public string Encrypt(string unencrypted)
    {
        return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
    }

    public string Decrypt(string encrypted)
    {
        return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
    }

    public byte[] Encrypt(byte[] buffer)
    {
        return Transform(buffer, encryptor);
    }

    public byte[] Decrypt(byte[] buffer)
    {
        return Transform(buffer, decryptor);
    }

    protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
    {
        MemoryStream stream = new MemoryStream();
        using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
        {
            cs.Write(buffer, 0, buffer.Length);
        }
        return stream.ToArray();
    }
}

2
Podczas dekodowania musiałem zastąpić spację znakiem +, aby działał z QueryString w Chrome: (new SimplerAES ()). Deszyfruj (Request.QueryString ["myParam"]. Zamień ('', '+'));
live-love

20
Nigdy nie używaj stałego wektora inicjalizacji, zobacz: crypto.stackexchange.com/questions/66/…, aby uzyskać więcej informacji o tym, dlaczego. Zamiast tego wygeneruj nowy IV dla każdego szyfrowania i dołącz go do kryptotekstu, o wiele lepiej i nie za mocno.
Tom Heard,

2
Należy pamiętać, że dane wyjściowe metody EncryptToUrl w tym rozwiązaniu (lub jakiekolwiek użycie podstawowego ciągu 64 znaków UrlEncoded w ogóle) nie będzie domyślnie działać w IIS 7, gdy jest używany jako część ścieżki URL (nie ciąg zapytania), jak w trasa ASP.NET MVC ze względu na ustawienie zabezpieczeń IIS 7. Aby uzyskać więcej informacji, zobacz: stackoverflow.com/a/2014121/12484
Jon Schneider

5
@TomHeard Jak można to zrobić z powyższym kodem?
MKII

26
Ostrzeżenie bezpieczeństwa: nie używaj tego kodu Patrz komentarz @TomHeard
jbtule

36

Tak, dodaj System.Securityzestaw, zaimportuj System.Security.Cryptographyprzestrzeń nazw. Oto prosty przykład szyfrowania algorytmem symetrycznym (DES):

DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.GenerateKey();
byte[] key = des.Key; // save this!

ICryptoTransform encryptor = des.CreateEncryptor();
// encrypt
byte[] enc = encryptor.TransformFinalBlock(new byte[] { 1, 2, 3, 4 }, 0, 4);

ICryptoTransform decryptor = des.CreateDecryptor();

// decrypt
byte[] originalAgain = decryptor.TransformFinalBlock(enc, 0, enc.Length);
Debug.Assert(originalAgain[0] == 1);

5
To ładne, kompaktowe dwukierunkowe szyfrowanie. Jedynym zastrzeżeniem jest to, że DES nie jest już uważany za najnowocześniejszy system bezpieczeństwa. Ten tytuł należy teraz do algorytmu AES, który omawiam poniżej.
Mark Brittingham,

@richdiet. Przepraszam, nie zaakceptowałem twojej odpowiedzi. Druga odpowiedź z ponad 37 głosami, ponieważ jest bardziej aktualna. Dziękuję za odpowiedź, ponieważ nadal jest dobra.
Matt Dawdy

14
@ MarkBrittingham: każdy szyfr blokowy bez funkcji łączenia bloków, wektora inicjalizacji i właściwego wypełnienia jest niepewny. Korzystanie z DES jest najmniej ważnym problemem w tym schemacie.
Hubert Kario

2
Więc gdzie jest używany klucz?
Alex

22
Ostrzeżenie bezpieczeństwa: nie używaj tego kodu Patrz komentarz @HubertKario
jbtule

28

Pomyślałem, że dodam, że ulepszyłem Mud's SimplerAES, dodając losowy IV, który jest przekazywany z powrotem do zaszyfrowanego ciągu. Poprawia to szyfrowanie, ponieważ szyfrowanie tego samego ciągu spowoduje za każdym razem inne wyjście.

public class StringEncryption
{
    private readonly Random random;
    private readonly byte[] key;
    private readonly RijndaelManaged rm;
    private readonly UTF8Encoding encoder;

    public StringEncryption()
    {
        this.random = new Random();
        this.rm = new RijndaelManaged();
        this.encoder = new UTF8Encoding();
        this.key = Convert.FromBase64String("Your+Secret+Static+Encryption+Key+Goes+Here=");
    }

    public string Encrypt(string unencrypted)
    {
        var vector = new byte[16];
        this.random.NextBytes(vector);
        var cryptogram = vector.Concat(this.Encrypt(this.encoder.GetBytes(unencrypted), vector));
        return Convert.ToBase64String(cryptogram.ToArray());
    }

    public string Decrypt(string encrypted)
    {
        var cryptogram = Convert.FromBase64String(encrypted);
        if (cryptogram.Length < 17)
        {
            throw new ArgumentException("Not a valid encrypted string", "encrypted");
        }

        var vector = cryptogram.Take(16).ToArray();
        var buffer = cryptogram.Skip(16).ToArray();
        return this.encoder.GetString(this.Decrypt(buffer, vector));
    }

    private byte[] Encrypt(byte[] buffer, byte[] vector)
    {
        var encryptor = this.rm.CreateEncryptor(this.key, vector);
        return this.Transform(buffer, encryptor);
    }

    private byte[] Decrypt(byte[] buffer, byte[] vector)
    {
        var decryptor = this.rm.CreateDecryptor(this.key, vector);
        return this.Transform(buffer, decryptor);
    }

    private byte[] Transform(byte[] buffer, ICryptoTransform transform)
    {
        var stream = new MemoryStream();
        using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
        {
            cs.Write(buffer, 0, buffer.Length);
        }

        return stream.ToArray();
    }
}

I test jednostkowy premii

[Test]
public void EncryptDecrypt()
{
    // Arrange
    var subject = new StringEncryption();
    var originalString = "Testing123!£$";

    // Act
    var encryptedString1 = subject.Encrypt(originalString);
    var encryptedString2 = subject.Encrypt(originalString);
    var decryptedString1 = subject.Decrypt(encryptedString1);
    var decryptedString2 = subject.Decrypt(encryptedString2);

    // Assert
    Assert.AreEqual(originalString, decryptedString1, "Decrypted string should match original string");
    Assert.AreEqual(originalString, decryptedString2, "Decrypted string should match original string");
    Assert.AreNotEqual(originalString, encryptedString1, "Encrypted string should not match original string");
    Assert.AreNotEqual(encryptedString1, encryptedString2, "String should never be encrypted the same twice");
}

11
1) Nie używaj System.Randomjako RNG. 2) Jest to całkowicie złamane przeciwko atakom na wybrany
tekst

21
Ostrzeżenie bezpieczeństwa: nie używaj tego kodu, patrz powyżej komentarz @CodesInChaos
jbtule

@jbtule, proszę, nie wprowadzaj w błąd każdej osoby, która nie chce komplikacji, po prostu szyfruj, a także, która nie obawia się ataku, - Proszę nie zamawiać, jeśli chcesz dać sugestię.
Virbhadrasinh

@Virbhadrasinh z mojej strony nie mam wątpliwości, w rzeczywistości jest wręcz przeciwnie. Jeśli zamierzasz korzystać z AES, prawidłowe użycie go jest dość ważne, niewłaściwe użycie i stwierdzenie, że nie mam nic przeciwko, używam go źle.
jbtule

1
@Corey Nie krzyczy i postępował zgodnie z najlepszymi praktykami dotyczącymi rozwiązywania problemów związanych z bezpieczeństwem w odpowiedziach na przepełnienie stosu. Jeśli chcesz link, został opublikowany w komentarzach do pytania. Ale umieszczę to tutaj również dla ciebie stackoverflow.com/a/10366194/637783
jbtule

12

Wariant Znaków (doskonała) odpowiedź

  • Dodaj „za pomocą”
  • Uczyń klasę IDisposable
  • Usuń kodowanie adresu URL, aby uprościć przykład.
  • Dodaj proste urządzenie testowe, aby zademonstrować użycie

Mam nadzieję że to pomoże

[TestFixture]
public class RijndaelHelperTests
{
    [Test]
    public void UseCase()
    {
        //These two values should not be hard coded in your code.
        byte[] key = {251, 9, 67, 117, 237, 158, 138, 150, 255, 97, 103, 128, 183, 65, 76, 161, 7, 79, 244, 225, 146, 180, 51, 123, 118, 167, 45, 10, 184, 181, 202, 190};
        byte[] vector = {214, 11, 221, 108, 210, 71, 14, 15, 151, 57, 241, 174, 177, 142, 115, 137};

        using (var rijndaelHelper = new RijndaelHelper(key, vector))
        {
            var encrypt = rijndaelHelper.Encrypt("StringToEncrypt");
            var decrypt = rijndaelHelper.Decrypt(encrypt);
            Assert.AreEqual("StringToEncrypt", decrypt);
        }
    }
}

public class RijndaelHelper : IDisposable
{
    Rijndael rijndael;
    UTF8Encoding encoding;

    public RijndaelHelper(byte[] key, byte[] vector)
    {
        encoding = new UTF8Encoding();
        rijndael = Rijndael.Create();
        rijndael.Key = key;
        rijndael.IV = vector;
    }

    public byte[] Encrypt(string valueToEncrypt)
    {
        var bytes = encoding.GetBytes(valueToEncrypt);
        using (var encryptor = rijndael.CreateEncryptor())
        using (var stream = new MemoryStream())
        using (var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
        {
            crypto.Write(bytes, 0, bytes.Length);
            crypto.FlushFinalBlock();
            stream.Position = 0;
            var encrypted = new byte[stream.Length];
            stream.Read(encrypted, 0, encrypted.Length);
            return encrypted;
        }
    }

    public string Decrypt(byte[] encryptedValue)
    {
        using (var decryptor = rijndael.CreateDecryptor())
        using (var stream = new MemoryStream())
        using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Write))
        {
            crypto.Write(encryptedValue, 0, encryptedValue.Length);
            crypto.FlushFinalBlock();
            stream.Position = 0;
            var decryptedBytes = new Byte[stream.Length];
            stream.Read(decryptedBytes, 0, decryptedBytes.Length);
            return encoding.GetString(decryptedBytes);
        }
    }

    public void Dispose()
    {
        if (rijndael != null)
        {
            rijndael.Dispose();
        }
    }
}

Dobra odpowiedź. Jedną rzeczą w metodzie Dispose będziesz musiał rzucić Rijndael na IDisposable, inaczej dostaniesz błąd na poziomie ochrony, dzwoniąc Dispose
John ClearZ

8
Nigdy nie używaj stałego wektora inicjalizacji, zobacz: crypto.stackexchange.com/questions/66/…, aby uzyskać więcej informacji o tym, dlaczego. Zamiast tego wygeneruj nowy IV dla każdego szyfrowania i dołącz go do kryptotekstu, o wiele lepiej i nie za mocno.
Tom Heard,

5
@Chalky Podczas szyfrowania używasz klasy Rijndael, aby wygenerować dla ciebie losową IV ( msdn.microsoft.com/en-us/library/... ), wykonaj szyfrowanie, a następnie pobierz IV z instancji Rijndael za pomocą właściwości IV . Następnie dodajesz (lub dołączasz, albo działa, dopóki odszyfrowuje go z tej samej strony) do tekstu kryptograficznego. Po odszyfrowaniu wyciągasz IV z otrzymanych danych (wielkość właściwości IV jest taka sama jak właściwość BlockSize podzielona przez 8), a następnie przekazujesz ją do instancji odszyfrowującej przed odszyfrowaniem.
Tom Heard

2
@Chalky Pamiętaj, że IV nie musi być tajne, musi być unikalne dla każdej wysłanej wiadomości.
Tom Heard

20
Ostrzeżenie bezpieczeństwa: nie używaj tego kodu Patrz wyżej Komentarze @TomHeard
jbtule

8

[EDYCJA] Wiele lat później wróciłem i powiedziałem: nie rób tego! Zobacz Co jest nie tak z szyfrowaniem XOR?dla szczegółów.

Bardzo prostym, łatwym dwukierunkowym szyfrowaniem jest szyfrowanie XOR.

  1. Wymyśl hasło. Niech tak będziemypass .
  2. Konwertuj hasło na binarne (zgodnie z ASCII). Hasło staje się 01101101 01111001 01110000 01100001 01110011 01110011.
  3. Weź wiadomość, którą chcesz zakodować. Przekształć to również w binarne.
  4. Spójrz na długość wiadomości. Jeśli długość wiadomości wynosi 400 bajtów, zmień hasło na ciąg 400 bajtów, powtarzając je w kółko. Stałoby się 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 ... (lubmypassmypassmypass... )
  5. XOR wiadomość z długim hasłem.
  6. Wyślij wynik.
  7. Innym razem XOR zaszyfrowaną wiadomość z tym samym hasłem (mypassmypassmypass... ).
  8. Oto twoja wiadomość!

10
@Ryan Nie każda sytuacja wymaga kryptograficznie bezpiecznych skrótów lub szyfrów Rijndael. „Proste szyfrowanie dwukierunkowe” może w rzeczywistości oznaczać proste , co sugeruje XOR, a nawet ROT13.

1
@ Ryan: AES ze statycznym kluczem szyfrującym, bez wektora inicjalizacji i bez funkcji łączenia bloków to tylko wymyślna nazwa dla szyfrowania XOR, po prostu używasz naprawdę wymyślnego KDF ...
Hubert Kario

17
Ostrzeżenie bezpieczeństwa: nie używaj tego kodu Szyfrowanie XOR z powtarzalnym kluczem jest trywialnie łamane.
jbtule

7

Połączyłem to, co uważałem za najlepsze, z kilku odpowiedzi i komentarzy.

  • Wektor losowej inicjalizacji poprzedzony tekstem kryptograficznym (@jbtule)
  • Użyj TransformFinalBlock () zamiast MemoryStream (@RenniePet)
  • Brak wstępnie wypełnionych kluczy, aby uniknąć kopiowania i wklejania katastrofy
  • Właściwe pozbywanie się i używanie wzorów

Kod:

/// <summary>
/// Simple encryption/decryption using a random initialization vector
/// and prepending it to the crypto text.
/// </summary>
/// <remarks>Based on multiple answers in http://stackoverflow.com/questions/165808/simple-two-way-encryption-for-c-sharp </remarks>
public class SimpleAes : IDisposable
{
    /// <summary>
    ///     Initialization vector length in bytes.
    /// </summary>
    private const int IvBytes = 16;

    /// <summary>
    ///     Must be exactly 16, 24 or 32 bytes long.
    /// </summary>
    private static readonly byte[] Key = Convert.FromBase64String("FILL ME WITH 24 (2 pad chars), 32 OR 44 (1 pad char) RANDOM CHARS"); // Base64 has a blowup of four-thirds (33%)

    private readonly UTF8Encoding _encoder;
    private readonly ICryptoTransform _encryptor;
    private readonly RijndaelManaged _rijndael;

    public SimpleAes()
    {
        _rijndael = new RijndaelManaged {Key = Key};
        _rijndael.GenerateIV();
        _encryptor = _rijndael.CreateEncryptor();
        _encoder = new UTF8Encoding();
    }

    public string Decrypt(string encrypted)
    {
        return _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
    }

    public void Dispose()
    {
        _rijndael.Dispose();
        _encryptor.Dispose();
    }

    public string Encrypt(string unencrypted)
    {
        return Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted)));
    }

    private byte[] Decrypt(byte[] buffer)
    {
        // IV is prepended to cryptotext
        byte[] iv = buffer.Take(IvBytes).ToArray();
        using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv))
        {
            return decryptor.TransformFinalBlock(buffer, IvBytes, buffer.Length - IvBytes);
        }
    }

    private byte[] Encrypt(byte[] buffer)
    {
        // Prepend cryptotext with IV
        byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); 
        return _rijndael.IV.Concat(inputBuffer).ToArray();
    }
}

Aktualizacja 2015-07-18: Naprawiono błąd w prywatnej metodzie Encrypt () w komentarzach @bpsilver i @Evereq. IV został przypadkowo zaszyfrowany, jest teraz poprzedzony czystym tekstem, zgodnie z oczekiwaniami Decrypt ().


Powinieneś zaszyfrować cały inputBuffer z IV poprzedzonym, w przeciwnym razie pierwsze 16 znaków ciągu do zaszyfrowania zostanie utraconych. Więc twój kod powinien brzmieć:return _encryptor.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
bpsilver

2
W takim przypadku:byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); return _rijndael.IV.Concat(inputBuffer).ToArray();
bpsilver

1
To zrobiłoby to samo, co obecne wdrożenie, prawda?
angularsen

1
„FILL ME 16, 24 LUB 32 CHARS” no, nie, nie wcześniej niż dekodowanie base 64. A klucz powinien być losowy. Naprawdę losowy.
Maarten Bodewes,

1
Zauważam, że @bpsilver ma rację i podany kod nie będzie działał bez jego poprawki: metoda szyfrowania zwraca zaszyfrowane dane bez IV (najpierw dodaje IV do bufora wejściowego, ale następnie szyfruje i zwraca dane bez niego). Jeśli to możliwe, po prostu zaktualizuj odpowiedź swoim kodem. (Uwaga: testuję tylko metody z parametrami bajt [], a nie ciągami). Dzięki!
Evereq

6

Jeśli chcesz po prostu prostego szyfrowania (tj. Możliwego do złamania określonego crackera, ale blokowania większości zwykłych użytkowników), po prostu wybierz dwa hasła o równej długości, powiedz:

deoxyribonucleicacid
while (x>0) { x-- };

i prześlij swoje dane za pomocą obu z nich (w razie potrzeby zapętlając hasła) (a) . Na przykład:

1111-2222-3333-4444-5555-6666-7777
deoxyribonucleicaciddeoxyribonucle
while (x>0) { x-- };while (x>0) { 

Ktoś, kto przeszukuje twój plik binarny, może pomyśleć, że łańcuch DNA jest kluczem, ale raczej nie przypuszcza, że ​​kod C to coś innego niż niezainicjowana pamięć zapisana z twoim plikiem binarnym.


(a) Należy pamiętać, że jest to bardzo proste szyfrowanie i, zgodnie z niektórymi definicjami, może wcale nie być traktowane jako szyfrowanie (ponieważ celem szyfrowania jest zapobieganie raczej nieautoryzowanemu dostępowi, niż tylko utrudnienie). Chociaż oczywiście nawet najsilniejsze szyfrowanie jest niepewne, gdy ktoś stoi nad uchwytami na klucze za pomocą stalowej rury.

Jak stwierdzono w pierwszym zdaniu, jest to sposób na utrudnienie przypadkowemu napastnikowi, aby ruszył dalej. Przypomina to zapobieganie włamaniom w twoim domu - nie musisz sprawiać, by był nie do zdobycia, musisz tylko uczynić go mniejszym niż dom obok :-)


3
Ciekawy pomysł. Nie jestem pewien, czy uwierzę w kod źródłowy w pliku binarnym - ale co powiesz na dostosowanie pomysłu do użycia komunikatu o błędzie jako hasła?
Jon Skeet

1
Wolę używać skrótu md5 z ciągiem czystego tekstu, który już istnieje w aplikacji (komunikat o błędzie lub mniej więcej).
Treb

2
Dlaczego muszą być równej długości? Właściwie wydaje się lepiej, jeśli mają różne długości. W ten sposób długość efektywnego operandu XOR wynosi LCM (długość1, długość2), a nie tylko długość1 (= długość2). Która oczywiście staje się długością1 * długość2, jeśli długości są względnie pierwsze.
Fantius

15
Ostrzeżenie o bezpieczeństwie: nie używaj tego kodu Klucz wielokrotnego użytku XOR można łatwo wyłamać dzięki pewnej ogólnej wiedzy na temat szyfrowanych danych.
jbtule

3
@jbtule, jeśli przeczytasz pytanie, zdasz sobie sprawę, że bezpieczniejsze szyfrowanie nie było w żaden sposób wymagane. W szczególności odniesienie do „prostego szyfrowania”, „niekrytycznego dla misji” i po prostu „utrzymywania uczciwych ludzi uczciwych”. Powinieneś także przeczytać mój pierwszy akapit, który wyraźnie mówi, że nie zablokuje on zdecydowanych napastników.
paxdiablo

5

Szyfrowanie jest łatwe: jak zauważyli inni, w przestrzeni nazw System.Security.Cryptography istnieją klasy, które wykonują całą pracę za Ciebie. Używaj ich zamiast domowych rozwiązań.

Ale odszyfrowanie jest również łatwe. Problemem nie jest algorytm szyfrowania, ale ochrona dostępu do klucza używanego do odszyfrowywania.

Użyłbym jednego z następujących rozwiązań:

  • DPAPI przy użyciu klasy ProtectedData z zakresem CurrentUser. Jest to łatwe, ponieważ nie musisz martwić się o klucz. Dane mogą być odszyfrowane tylko przez tego samego użytkownika, więc nie nadaje się do udostępniania danych między użytkownikami lub komputerami.

  • DPAPI przy użyciu klasy ProtectedData z zakresem LocalMachine. Dobry np. Do ochrony danych konfiguracyjnych na jednym bezpiecznym serwerze. Ale każdy, kto może zalogować się do komputera, może go zaszyfrować, więc nic dobrego, chyba że serwer jest bezpieczny.

  • Dowolny algorytm symetryczny. Zazwyczaj używam statycznej metody SymmetricAl Algorytm.Create (), jeśli nie dbam o to, który algorytm jest używany (w rzeczywistości jest to domyślnie Rijndael). W takim przypadku musisz jakoś zabezpieczyć swój klucz. Np. Możesz go w jakiś sposób zaciemnić i ukryć w swoim kodzie. Pamiętaj jednak, że każdy, kto jest wystarczająco inteligentny, aby zdekompilować kod, prawdopodobnie będzie w stanie znaleźć klucz.


5

Chciałem opublikować swoje rozwiązanie, ponieważ żadne z powyższych rozwiązań nie jest tak proste jak moje. Powiedz mi co myślisz:

 // This will return an encrypted string based on the unencrypted parameter
 public static string Encrypt(this string DecryptedValue)
 {
      HttpServerUtility.UrlTokenEncode(MachineKey.Protect(Encoding.UTF8.GetBytes(DecryptedValue.Trim())));
 }

 // This will return an unencrypted string based on the parameter
 public static string Decrypt(this string EncryptedValue)
 {
      Encoding.UTF8.GetString(MachineKey.Unprotect(HttpServerUtility.UrlTokenDecode(EncryptedValue)));
 }

Opcjonalny

Zakłada się, że klucz maszynowy serwera używanego do szyfrowania wartości jest taki sam, jak używany do odszyfrowywania wartości. W razie potrzeby możesz określić statyczny klucz maszynowy w pliku Web.config, aby aplikacja mogła odszyfrować / zaszyfrować dane bez względu na to, gdzie są uruchomione (np. Serwer programistyczny czy produkcyjny). Możesz wygenerować statyczny klucz maszynowy postępując zgodnie z tymi instrukcjami .


Uwaga: tego podejścia można użyć tylko w przypadku aplikacji ASP.NET.
Feru,

2

Przestrzeń nazw System.Security.Cryptographyzawiera klasy TripleDESCryptoServiceProvideriRijndaelManaged

Nie zapomnij dodać odniesienia do System.Securityzestawu.


8
Nie dlatego, że przegłosowałem, ale dlaczego wiek pytania powinien mieć znaczenie podczas głosowania?
user247702

2

Korzystanie z TripleDESCryptoServiceProvider w System.Security.Cryptography :

public static class CryptoHelper
{
    private const string Key = "MyHashString";
    private static TripleDESCryptoServiceProvider GetCryproProvider()
    {
        var md5 = new MD5CryptoServiceProvider();
        var key = md5.ComputeHash(Encoding.UTF8.GetBytes(Key));
        return new TripleDESCryptoServiceProvider() { Key = key, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
    }

    public static string Encrypt(string plainString)
    {
        var data = Encoding.UTF8.GetBytes(plainString);
        var tripleDes = GetCryproProvider();
        var transform = tripleDes.CreateEncryptor();
        var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length);
        return Convert.ToBase64String(resultsByteArray);
    }

    public static string Decrypt(string encryptedString)
    {
        var data = Convert.FromBase64String(encryptedString);
        var tripleDes = GetCryproProvider();
        var transform = tripleDes.CreateDecryptor();
        var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length);
        return Encoding.UTF8.GetString(resultsByteArray);
    }
}

1

Zmieniłem to :

public string ByteArrToString(byte[] byteArr)
{
    byte val;
    string tempStr = "";
    for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
    {
        val = byteArr[i];
        if (val < (byte)10)
            tempStr += "00" + val.ToString();
        else if (val < (byte)100)
            tempStr += "0" + val.ToString();
        else
            tempStr += val.ToString();
    }
    return tempStr;
}

do tego:

    public string ByteArrToString(byte[] byteArr)
    {
        string temp = "";
        foreach (byte b in byteArr)
            temp += b.ToString().PadLeft(3, '0');
        return temp;
    }

1

Korzystając z wbudowanej biblioteki kryptograficznej .Net, ten przykład pokazuje, jak korzystać z Advanced Encryption Standard (AES).

using System;
using System.IO;
using System.Security.Cryptography;

namespace Aes_Example
{
    class AesExample
    {
        public static void Main()
        {
            try
            {

                string original = "Here is some data to encrypt!";

                // Create a new instance of the Aes
                // class.  This generates a new key and initialization 
                // vector (IV).
                using (Aes myAes = Aes.Create())
                {

                    // Encrypt the string to an array of bytes.
                    byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);

                    // Decrypt the bytes to a string.
                    string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);

                    //Display the original data and the decrypted data.
                    Console.WriteLine("Original:   {0}", original);
                    Console.WriteLine("Round Trip: {0}", roundtrip);
                }

            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
        }
        static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,byte[] IV)
        {
            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");
            byte[] encrypted;
            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream.
            return encrypted;

        }

        static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

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

                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {

                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }

            }

            return plaintext;

        }
    }
}

0

Wiem, że powiedziałeś, że nie obchodzi Cię, jak bezpieczne jest, ale jeśli wybierzesz DES , równie dobrze możesz wziąć AES , jest to bardziej aktualna metoda szyfrowania.


0

Korzystam z akceptowanej odpowiedzi Marka Brittinghama, która bardzo mi pomogła. Ostatnio musiałem wysłać zaszyfrowany tekst do innej organizacji i właśnie tam pojawiły się pewne problemy. OP nie wymaga tych opcji, ale ponieważ jest to popularne pytanie, zamieszczam swoją modyfikację ( Encrypti Decryptfunkcje zapożyczone stąd ):

  1. Różne IV dla każdej wiadomości - Łączy bajty IV z bajtami szyfru przed uzyskaniem heksadecymalnego. Oczywiście jest to konwencja, którą należy przekazać stronom otrzymującym tekst zaszyfrowany.
  2. Umożliwia dwa konstruktory - jeden dla RijndaelManagedwartości domyślnych i jeden, w którym można określić wartości właściwości (na podstawie wzajemnego porozumienia między stronami szyfrującymi i deszyfrującymi)

Oto klasa (próbka testowa na końcu):

/// <summary>
/// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx
/// Uses UTF8 Encoding
///  http://security.stackexchange.com/a/90850
/// </summary>
public class AnotherAES : IDisposable
{
    private RijndaelManaged rijn;

    /// <summary>
    /// Initialize algo with key, block size, key size, padding mode and cipher mode to be known.
    /// </summary>
    /// <param name="key">ASCII key to be used for encryption or decryption</param>
    /// <param name="blockSize">block size to use for AES algorithm. 128, 192 or 256 bits</param>
    /// <param name="keySize">key length to use for AES algorithm. 128, 192, or 256 bits</param>
    /// <param name="paddingMode"></param>
    /// <param name="cipherMode"></param>
    public AnotherAES(string key, int blockSize, int keySize, PaddingMode paddingMode, CipherMode cipherMode)
    {
        rijn = new RijndaelManaged();
        rijn.Key = Encoding.UTF8.GetBytes(key);
        rijn.BlockSize = blockSize;
        rijn.KeySize = keySize;
        rijn.Padding = paddingMode;
        rijn.Mode = cipherMode;
    }

    /// <summary>
    /// Initialize algo just with key
    /// Defaults for RijndaelManaged class: 
    /// Block Size: 256 bits (32 bytes)
    /// Key Size: 128 bits (16 bytes)
    /// Padding Mode: PKCS7
    /// Cipher Mode: CBC
    /// </summary>
    /// <param name="key"></param>
    public AnotherAES(string key)
    {
        rijn = new RijndaelManaged();
        byte[] keyArray = Encoding.UTF8.GetBytes(key);
        rijn.Key = keyArray;
    }

    /// <summary>
    /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx
    /// Encrypt a string using RijndaelManaged encryptor.
    /// </summary>
    /// <param name="plainText">string to be encrypted</param>
    /// <param name="IV">initialization vector to be used by crypto algorithm</param>
    /// <returns></returns>
    public byte[] Encrypt(string plainText, byte[] IV)
    {
        if (rijn == null)
            throw new ArgumentNullException("Provider not initialized");

        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText cannot be null or empty");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV cannot be null or empty");
        byte[] encrypted;

        // Create a decrytor to perform the stream transform.
        using (ICryptoTransform encryptor = rijn.CreateEncryptor(rijn.Key, IV))
        {
            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        // Return the encrypted bytes from the memory stream.
        return encrypted;
    }//end EncryptStringToBytes

    /// <summary>
    /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx
    /// </summary>
    /// <param name="cipherText">bytes to be decrypted back to plaintext</param>
    /// <param name="IV">initialization vector used to encrypt the bytes</param>
    /// <returns></returns>
    public string Decrypt(byte[] cipherText, byte[] IV)
    {
        if (rijn == null)
            throw new ArgumentNullException("Provider not initialized");

        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText cannot be null or empty");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV cannot be null or empty");

        // Declare the string used to hold the decrypted text.
        string plaintext = null;

        // Create a decrytor to perform the stream transform.
        using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijn.Key, IV))
        {
            // Create the streams used for decryption.
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        // Read the decrypted bytes from the decrypting stream and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }

        return plaintext;
    }//end DecryptStringFromBytes

    /// <summary>
    /// Generates a unique encryption vector using RijndaelManaged.GenerateIV() method
    /// </summary>
    /// <returns></returns>
    public byte[] GenerateEncryptionVector()
    {
        if (rijn == null)
            throw new ArgumentNullException("Provider not initialized");

        //Generate a Vector
        rijn.GenerateIV();
        return rijn.IV;
    }//end GenerateEncryptionVector


    /// <summary>
    /// Based on https://stackoverflow.com/a/1344255
    /// Generate a unique string given number of bytes required.
    /// This string can be used as IV. IV byte size should be equal to cipher-block byte size. 
    /// Allows seeing IV in plaintext so it can be passed along a url or some message.
    /// </summary>
    /// <param name="numBytes"></param>
    /// <returns></returns>
    public static string GetUniqueString(int numBytes)
    {
        char[] chars = new char[62];
        chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
        byte[] data = new byte[1];
        using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
        {
            data = new byte[numBytes];
            crypto.GetBytes(data);
        }
        StringBuilder result = new StringBuilder(numBytes);
        foreach (byte b in data)
        {
            result.Append(chars[b % (chars.Length)]);
        }
        return result.ToString();
    }//end GetUniqueKey()

    /// <summary>
    /// Converts a string to byte array. Useful when converting back hex string which was originally formed from bytes.
    /// </summary>
    /// <param name="hex"></param>
    /// <returns></returns>
    public static byte[] StringToByteArray(String hex)
    {
        int NumberChars = hex.Length;
        byte[] bytes = new byte[NumberChars / 2];
        for (int i = 0; i < NumberChars; i += 2)
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        return bytes;
    }//end StringToByteArray

    /// <summary>
    /// Dispose RijndaelManaged object initialized in the constructor
    /// </summary>
    public void Dispose()
    {
        if (rijn != null)
            rijn.Dispose();
    }//end Dispose()
}//end class

i..

Oto próbka testowa:

class Program
{
    string key;
    static void Main(string[] args)
    {
        Program p = new Program();

        //get 16 byte key (just demo - typically you will have a predetermined key)
        p.key = AnotherAES.GetUniqueString(16);

        string plainText = "Hello World!";

        //encrypt
        string hex = p.Encrypt(plainText);

        //decrypt
        string roundTrip = p.Decrypt(hex);

        Console.WriteLine("Round Trip: {0}", roundTrip);
    }

    string Encrypt(string plainText)
    {
        Console.WriteLine("\nSending (encrypt side)...");
        Console.WriteLine("Plain Text: {0}", plainText);
        Console.WriteLine("Key: {0}", key);
        string hex = string.Empty;
        string ivString = AnotherAES.GetUniqueString(16);
        Console.WriteLine("IV: {0}", ivString);
        using (AnotherAES aes = new AnotherAES(key))
        {
            //encrypting side
            byte[] IV = Encoding.UTF8.GetBytes(ivString);

            //get encrypted bytes (IV bytes prepended to cipher bytes)
            byte[] encryptedBytes = aes.Encrypt(plainText, IV);
            byte[] encryptedBytesWithIV = IV.Concat(encryptedBytes).ToArray();

            //get hex string to send with url
            //this hex has both IV and ciphertext
            hex = BitConverter.ToString(encryptedBytesWithIV).Replace("-", "");
            Console.WriteLine("sending hex: {0}", hex);
        }

        return hex;
    }

    string Decrypt(string hex)
    {
        Console.WriteLine("\nReceiving (decrypt side)...");
        Console.WriteLine("received hex: {0}", hex);
        string roundTrip = string.Empty;
        Console.WriteLine("Key " + key);
        using (AnotherAES aes = new AnotherAES(key))
        {
            //get bytes from url
            byte[] encryptedBytesWithIV = AnotherAES.StringToByteArray(hex);

            byte[] IV = encryptedBytesWithIV.Take(16).ToArray();

            Console.WriteLine("IV: {0}", System.Text.Encoding.Default.GetString(IV));

            byte[] cipher = encryptedBytesWithIV.Skip(16).ToArray();

            roundTrip = aes.Decrypt(cipher, IV);
        }
        return roundTrip;
    }
}

wprowadź opis zdjęcia tutaj


-2

Myślę, że to najprostszy na świecie!

string encrypted = "Text".Aggregate("", (c, a) => c + (char) (a + 2));

Test

 Console.WriteLine(("Hello").Aggregate("", (c, a) => c + (char) (a + 1)));
            //Output is Ifmmp
 Console.WriteLine(("Ifmmp").Aggregate("", (c, a) => c + (char)(a - 1)));
            //Output is Hello

ROT ... 1? Naprawdę? OP powołał się nawet na ROT13 jako przykład tego, czego nie chciał robić.
user812786
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.