Dữ liệu hai chiều đơn giản không an toàn.


426

Tôi đang tìm kiếm chức năng obfuscation rất đơn giản (như mã hóa và giải mã nhưng không nhất thiết phải bảo mật) cho một số dữ liệu. Đó không phải là nhiệm vụ quan trọng. Tôi cần một cái gì đó để giữ cho những người trung thực thành thật, nhưng một cái gì đó mạnh hơn một chút so với ROT13 hoặc Base64 .

Tôi thích cái gì đó đã được bao gồm trong .NET framework 2.0, vì vậy tôi không phải lo lắng về bất kỳ sự phụ thuộc bên ngoài nào.

Tôi thực sự không muốn phải loay hoay với các khóa công khai / riêng tư, v.v. Tôi không biết nhiều về mã hóa, nhưng tôi biết đủ để biết rằng bất cứ điều gì tôi viết sẽ ít hơn vô giá trị ... Thực tế, Có lẽ tôi đã làm hỏng toán học và biến nó thành chuyện nhỏ.


3
Xin chào Mark - không vấn đề gì. Tôi cảm thấy tồi tệ vì tôi đã không chấp nhận câu trả lời từ richdiet, vì tôi thực sự đã sử dụng giải pháp của anh ấy và nó hoạt động rất tốt. Tuy nhiên, tôi tiếp tục quay lại đây để đọc các câu trả lời khác, và câu trả lời của bạn thực sự tốt hơn. Không có lý do để nói với mọi người sử dụng một cái gì đó, trong khi nó hoạt động, không thực sự là một cách tuyệt vời để làm một cái gì đó khi có sẵn một câu trả lời tốt hơn.
Matt Dawdy

3
Hãy tiết kiệm thời gian của bạn và sử dụng HTTPServerUtility.UrlTokenEn / Giải mã để chuyển đổi qua lại từ các mảng byte thành một chuỗi thân thiện với url.
Praesagus

32
+1 vì không cố gắng thiết kế thông minh của riêng bạn. Bạn có thể không biết nhiều về mã hóa, nhưng thực tế là bạn biết rằng điều đó giúp bạn vượt lên trên hầu hết các nhà phát triển mà tôi đã gặp, những người không biết nhiều về mã hóa nhưng nghĩ rằng họ có thể tạo ra giải pháp của riêng họ.
Dinah

6
Chú ý: Nhiều câu trả lời trong câu hỏi này chỉ là mã hóa không được xác thực. Điều này có nghĩa là kẻ tấn công có thể thay đổi dữ liệu mà không cần thông báo ứng dụng . Nó cũng dẫn đến các lỗ hổng nghiêm trọng khác (như giải mã mà không có khóa do nhà tiên tri đệm). TL; DR: Không sử dụng mã trong các câu trả lời được đưa ra nếu bạn không ổn với điều đó hoặc không hiểu những gì tôi vừa nói.
usr

36
Không có một câu trả lời cho câu hỏi này mô tả mã hóa an toàn. Sử dụng câu trả lời của jbtule tại Encrypt và giải mã một chuỗi thay thế.
CodeInChaos

Câu trả lời:


471

Các câu trả lời khác ở đây hoạt động tốt, nhưng AES là một thuật toán mã hóa an toàn và cập nhật hơn. Đây là lớp mà tôi đã thu được vài năm trước để thực hiện mã hóa AES mà tôi đã sửa đổi theo thời gian để thân thiện hơn với các ứng dụng web (e, g. Tôi đã xây dựng các phương thức Mã hóa / Giải mã hoạt động với chuỗi thân thiện với URL). Nó cũng có các phương thức hoạt động với mảng byte.

LƯU Ý: bạn nên sử dụng các giá trị khác nhau trong mảng Khóa (32 byte) và Vector (16 byte)! Bạn sẽ không muốn ai đó tìm ra chìa khóa của mình bằng cách giả sử rằng bạn đã sử dụng mã này như hiện tại! Tất cả những gì bạn phải làm là thay đổi một số số (phải là <= 255) trong mảng Khóa và Vector (Tôi đã để lại một giá trị không hợp lệ trong mảng Vector để đảm bảo bạn làm điều này ...). Bạn có thể sử dụng https://www.random.org/bytes/ để tạo một bộ mới một cách dễ dàng:

Sử dụng nó rất dễ dàng: chỉ cần khởi tạo lớp và sau đó gọi (thường là) EncryptToString (chuỗi StringToEncrypt) và DecryptString (chuỗi StringToDecrypt) làm phương thức. Không thể dễ dàng hơn (hoặc an toàn hơn) khi bạn có lớp học này.


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 - Điều đó được thực hiện trên mục đích để bạn thay đổi các giá trị trong mảng, như Mark ghi chú trong đoạn thứ hai.
Pauk

42
Bạn không nên sử dụng IV như thế này. Đối với hai tin nhắn đã cho, chúng không nên được mã hóa bằng cùng một Khóa và cùng IV. IV nên là ngẫu nhiên cho mỗi tin nhắn, được thêm vào tiền điện tử và đọc trước khi giải mã. crypto.stackexchange.com/a/82/1934
jbtule

30
Sử dụng IV ngẫu nhiên cho mỗi thông báo không phải là kỳ lạ hay mới, chỉ là quan trọng và là một phần của thiết kế thuật toán. Sử dụng IV có thể dự đoán cho mọi tin nhắn là một lỗi phổ biến về tiền điện tử không cần phải xử lý.
jbtule

14
Cũng lưu ý rằng hậu quả của việc sử dụng CBC làm chế độ của nó là bạn có khả năng dễ bị tấn công bởi các cuộc tấn công sấm sét . Sử dụng mã hóa được xác thực và bất cứ khi nào có thể, đừng tự mình thực hiện mật mã .
Stephen Touset

57
Cảnh báo bảo mật: Không sử dụng mã này Mặc dù là câu trả lời được chấp nhận, có những vấn đề bảo mật nghiêm trọng được đề cập trong các ý kiến ​​trên mà tác giả đã tiếp tục bỏ qua trong 8 năm.
jbtule

176

Tôi đã dọn dẹp SimpleAES (ở trên) để sử dụng. Đã sửa lỗi các phương thức mã hóa / giải mã phức tạp; các phương thức riêng biệt để mã hóa bộ đệm byte, chuỗi và chuỗi thân thiện với URL; đã sử dụng các thư viện hiện có để mã hóa URL.

Mã nhỏ, đơn giản hơn, nhanh hơn và đầu ra ngắn gọn hơn. Chẳng hạn, johnsmith@gmail.comtạo ra:

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

Mã số:

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
Khi giải mã, tôi phải thay thế dung lượng bằng + để nó hoạt động với QueryString trong Chrome: (SimplerAES mới ()). Giải mã (Request.QueryString ["myParam"]. Thay thế ('', '+'));
tình yêu trực tiếp

20
Đừng bao giờ sử dụng Vector khởi tạo liên tục, xem: crypto.stackexchange.com/questions/66/ đá để biết thêm thông tin về lý do tại sao. Thay vào đó, hãy tạo IV mới cho mỗi mã hóa và nối nó vào tiền điện tử, tốt hơn nhiều và không khó.
Tom Nghe

2
Xin lưu ý rằng đầu ra của phương thức EncryptToUrl trong giải pháp này (hoặc bất kỳ việc sử dụng chuỗi 64 cơ sở UrlEncoding nói chung) sẽ không hoạt động theo mặc định trong IIS 7 khi được sử dụng như một phần của đường dẫn URL (không phải chuỗi truy vấn), như trong một tuyến ASP.NET MVC, do cài đặt bảo mật IIS 7. Để biết thêm, hãy xem: stackoverflow.com/a/2014121/12484
Jon Schneider

5
@TomHeard Làm thế nào một người sẽ làm điều đó, với đoạn mã trên?
MKII

26
Cảnh báo bảo mật: Không sử dụng mã này Xem bình luận của @TomHeard
jbtule

36

Có, thêm System.Securitylắp ráp, nhập System.Security.Cryptographykhông gian tên. Đây là một ví dụ đơn giản về mã hóa thuật toán đối xứng (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
Đây là một mã hóa hai chiều nhỏ gọn, đẹp. Nhắc nhở duy nhất là DES không còn được coi là bảo mật tối tân. Tiêu đề đó bây giờ thuộc về thuật toán AES mà tôi thảo luận dưới đây.
Mark Britsham

@richdiet. Tôi xin lỗi tôi không chấp nhận câu trả lời của bạn. Câu trả lời khác với hơn 37 phiếu bầu vì nó hiện tại hơn. Cảm ơn câu trả lời của bạn, vì nó vẫn là một câu hỏi hay.
Matt Dawdy

14
@MarkBrittingham: bất kỳ mật mã khối nào không có chức năng tạo chuỗi khối, vectơ khởi tạo và phần đệm thích hợp là không an toàn. Sử dụng DES là vấn đề ít quan trọng nhất với sơ đồ này.
Hubert Kario

2
Vậy chìa khóa được sử dụng ở đâu?
Alex

22
Cảnh báo bảo mật: Không sử dụng mã này Xem bình luận của @HubertKario
jbtule

28

Chỉ cần nghĩ rằng tôi đã thêm rằng tôi đã cải thiện Bộ mô phỏng của Mud bằng cách thêm một IV ngẫu nhiên được truyền lại bên trong chuỗi được mã hóa. Điều này cải thiện mã hóa vì mã hóa cùng một chuỗi sẽ dẫn đến một đầu ra khác nhau mỗi lần.

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();
    }
}

Và kiểm tra đơn vị tiền thưởng

[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) Không sử dụng System.Randomnhư RNG. 2) Điều này hoàn toàn bị phá vỡ đối với các cuộc tấn công mã hóa được chọn (đặc biệt là các phần tử đệm)
CodeInChaos

21
Cảnh báo bảo mật: Không sử dụng Mã này xem bình luận ở trên bởi @CodesInChaos
jbtule

@jbtule xin đừng nhầm lẫn với mọi người, những người không muốn phức tạp chỉ cần mã hóa, và cả những người không cảnh giác về cuộc tấn công, - Xin đừng đặt hàng nếu bạn muốn đưa ra gợi ý.
Virbhadrasinh

@Virbhadrasinh không có gì sai về phía tôi, thực tế nó hoàn toàn ngược lại. Nếu bạn định sử dụng AES, sử dụng đúng cách là khá quan trọng, sử dụng không chính xác và nói rằng không sao, tôi không sử dụng nó cho mục đích quan trọng, là sai lầm.
jbtule

1
@Corey Không la hét, và đã tuân theo cách thực hành tốt nhất để xử lý các vấn đề bảo mật trong câu trả lời tràn stack. Nếu bạn muốn một liên kết, nó đã được đăng trong các bình luận câu hỏi. Nhưng tôi cũng sẽ đặt nó ở đây cho bạn cũng như stackoverflow.com/a/10366194/637783
jbtule

12

Một biến thể của câu trả lời Marks (xuất sắc)

  • Thêm "bằng"
  • Tạo lớp IDis Dùng một lần
  • Xóa mã mã hóa URL để làm cho ví dụ đơn giản hơn.
  • Thêm một vật cố thử nghiệm đơn giản để chứng minh việc sử dụng

Hi vọng điêu nay co ich

[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();
        }
    }
}

Câu trả lời tốt. Một điều trong phương thức Vứt bỏ bạn sẽ cần truyền rijndael sang IDis Dùng hoặc bạn sẽ gặp lỗi cấp độ bảo vệ bằng cách gọi Vứt bỏ
John ClearZ

8
Đừng bao giờ sử dụng Vector khởi tạo liên tục, xem: crypto.stackexchange.com/questions/66/ đá để biết thêm thông tin về lý do tại sao. Thay vào đó, hãy tạo IV mới cho mỗi mã hóa và nối nó vào tiền điện tử, tốt hơn nhiều và không khó.
Tom Nghe

5
@Chalky Về mã hóa, bạn sử dụng lớp Rijndael để tạo IV ngẫu nhiên cho bạn ( msdn.microsoft.com/en-us/l Library / trộm ), thực hiện mã hóa của bạn và sau đó lấy IV từ đối tượng Rijndael bằng thuộc tính IV . Sau đó, bạn trả trước (hoặc nối thêm, hoặc hoạt động miễn là giải mã của bạn lấy nó từ cùng một phía) nó vào văn bản mật mã của bạn. Khi giải mã, sau đó bạn kéo IV từ dữ liệu nhận được (Kích thước của thuộc tính IV giống với thuộc tính BlockSize chia cho 8), sau đó chuyển nó vào thể hiện giải mã của bạn trước khi giải mã.
Tom Nghe

2
@Chalky Lưu ý rằng IV không cần phải bí mật, nó chỉ cần là duy nhất cho mỗi tin nhắn được gửi.
Tom Nghe

20
Cảnh báo bảo mật: Không sử dụng mã này Xem các bình luận ở trên bởi @TomHeard
jbtule

8

[EDIT] Nhiều năm sau, tôi quay lại nói: đừng làm điều này! Xem có gì sai với mã hóa XOR? để biết chi tiết.

Một mã hóa hai chiều rất đơn giản, dễ dàng là mã hóa XOR.

  1. Hãy đến với một mật khẩu. Chúng ta hãy có nó mypass.
  2. Chuyển đổi mật khẩu thành nhị phân (theo ASCII). Mật khẩu trở thành 01101101 01111001 01110000 01100001 01110011 01110011.
  3. Lấy thông điệp bạn muốn mã hóa. Chuyển đổi nó thành nhị phân, cũng có.
  4. Nhìn vào độ dài của tin nhắn. Nếu độ dài tin nhắn là 400 byte, hãy chuyển mật khẩu thành chuỗi 400 byte bằng cách lặp đi lặp lại nhiều lần. Nó sẽ trở thành 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 ... (hoặc mypassmypassmypass...)
  5. XOR tin nhắn với mật khẩu dài.
  6. Gửi kết quả.
  7. Một lần khác, XOR tin nhắn được mã hóa với cùng một mật khẩu ( mypassmypassmypass...).
  8. Có tin nhắn của bạn!

10
@Ryan Không phải mọi tình huống đều yêu cầu băm mật mã hoặc mật mã Rijndael. "Mã hóa 2 chiều đơn giản" thực sự có nghĩa là đơn giản , có nghĩa là xor hoặc thậm chí ROT13.

1
@Ryan: AES với khóa mã hóa tĩnh, không có vectơ khởi tạo và không có chức năng xâu chuỗi chỉ là tên ưa thích cho mã hóa XOR, bạn chỉ đang sử dụng KDF thực sự lạ mắt ...
Hubert Kario

17
Cảnh báo bảo mật: Không sử dụng Mã này Mã hóa XOR với khóa lặp lại bị bẻ khóa.
jbtule

7

Tôi kết hợp những gì tôi tìm thấy tốt nhất từ ​​một số câu trả lời và ý kiến.

  • Vectơ khởi tạo ngẫu nhiên được thêm vào văn bản tiền điện tử (@jbtule)
  • Sử dụng TransformFinalBlock () thay vì MemoryStream (@RenniePet)
  • Không có khóa được điền sẵn để tránh bất kỳ ai sao chép và dán thảm họa
  • Vứt bỏ và sử dụng đúng mẫu

Mã số:

/// <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();
    }
}

Cập nhật 2015-07-18: Đã sửa lỗi trong phương thức Mã hóa riêng tư () bằng nhận xét của @bpsilver và @Evereq. IV đã vô tình được mã hóa, hiện được thêm vào văn bản rõ ràng như mong đợi của Decrypt ().


Bạn nên mã hóa toàn bộ inputBuffer bằng IV được cấp trước nếu không 16 ký tự đầu tiên của chuỗi mã hóa sẽ bị mất. Vì vậy, mã của bạn nên đọc:return _encryptor.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
bpsilver 17/11/14

2
Trong trường hợp đó:byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); return _rijndael.IV.Concat(inputBuffer).ToArray();
bpsilver

1
Điều đó sẽ làm điều tương tự như việc thực hiện hiện tại, phải không?
angensesen

1
"HOÀN TOÀN VỚI 16, 24 HOẶC 32 CHARS", không, không phải trước khi giải mã cơ sở 64. Và một chìa khóa nên là ngẫu nhiên. Thực sự ngẫu nhiên.
Maarten Bodewes

1
Tôi nhận thấy rằng @bpsilver đúng và mã được cung cấp sẽ không hoạt động nếu không có cách khắc phục của anh ta: phương thức mã hóa trả về dữ liệu được mã hóa mà không cần IV (trước tiên, nó thêm IV vào bộ nạp dữ liệu, nhưng mã hóa tiếp theo và trả lại dữ liệu mà không có nó). Vì vậy, nếu có thể chỉ cần cập nhật câu trả lời với mã của mình. (Lưu ý: Tôi chỉ kiểm tra các phương thức với tham số byte [], không phải chuỗi). Cảm ơn!
Evereq 18/07/2015

6

Nếu bạn chỉ muốn mã hóa đơn giản (nghĩa là có thể để một cracker xác định bị phá vỡ, nhưng khóa hầu hết người dùng thông thường), chỉ cần chọn hai cụm mật khẩu có độ dài bằng nhau, nói:

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

và xor dữ liệu của bạn với cả hai (lặp các cụm mật khẩu nếu cần) (a) . Ví dụ:

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

Ai đó đang tìm kiếm nhị phân của bạn cũng có thể nghĩ rằng chuỗi DNA là một khóa, nhưng họ không thể nghĩ rằng mã C là bất cứ thứ gì khác ngoài bộ nhớ chưa được lưu trong bộ nhị phân của bạn.


(a) Hãy nhớ rằng đây là mã hóa rất đơn giản và theo một số định nghĩa, có thể hoàn toàn không được coi là mã hóa (vì mục đích của mã hóa là để ngăn chặn truy cập trái phép thay vì chỉ gây khó khăn hơn). Mặc dù, tất nhiên, ngay cả mã hóa mạnh nhất cũng không an toàn khi ai đó đứng trên giá đỡ chìa khóa bằng ống thép.

Như đã nói trong câu đầu tiên, đây là một phương tiện để gây khó khăn đủ cho kẻ tấn công thông thường mà chúng sẽ tiếp tục. Nó tương tự như ngăn chặn các vụ trộm tại nhà của bạn - bạn không cần phải làm cho nó bất khả xâm phạm, bạn chỉ cần làm cho nó ít mang thai hơn nhà bên cạnh :-)


3
Ý tưởng thú vị. Tôi không chắc chắn mình "tin" mã nguồn ở dạng nhị phân - nhưng làm thế nào để điều chỉnh ý tưởng sử dụng thông báo lỗi làm cụm mật khẩu?
Jon Skeet

1
Tôi thích sử dụng hàm băm md5 của một số chuỗi Cleartext đã tồn tại trong ứng dụng (thông báo lỗi hoặc như vậy).
Treb

2
Tại sao chúng cần phải có chiều dài bằng nhau? Nó thực sự có vẻ tốt hơn nếu chúng có độ dài khác nhau. Theo cách đó, độ dài của toán hạng XOR hiệu quả của bạn là LCM (length1, length2), thay vì chỉ length1 (= length2). Tất nhiên trở thành length1 * length2 nếu độ dài tương đối nguyên tố.
Fantius

15
Cảnh báo bảo mật: Không sử dụng mã này Lặp lại khóa XOR có thể dễ dàng bẻ khóa chỉ với một số kiến ​​thức chung về dữ liệu được mã hóa.
jbtule

3
@jbtule, nếu bạn đọc câu hỏi, bạn sẽ nhận ra rằng mã hóa an toàn hơn là không cần thiết. Cụ thể là tham chiếu đến 'mã hóa đơn giản', 'không phải là nhiệm vụ quan trọng' và chỉ 'giữ cho những người trung thực trung thực'. Bạn cũng nên đọc đoạn đầu tiên của tôi trong đó gọi rõ ràng thực tế là nó sẽ không khóa những kẻ tấn công xác định.
paxdiablo

5

Mã hóa rất dễ dàng: như những người khác đã chỉ ra, có các lớp trong không gian tên System.Security.Cryptography thực hiện tất cả công việc cho bạn. Sử dụng chúng hơn là bất kỳ giải pháp trồng tại nhà.

Nhưng giải mã cũng dễ dàng. Vấn đề bạn gặp phải không phải là thuật toán mã hóa, mà là bảo vệ quyền truy cập vào khóa được sử dụng để giải mã.

Tôi sẽ sử dụng một trong những giải pháp sau:

  • DPAPI sử dụng lớp ProtectedData với phạm vi CurrentUser. Điều này thật dễ dàng vì bạn không cần phải lo lắng về chìa khóa. Dữ liệu chỉ có thể được giải mã bởi cùng một người dùng, vì vậy không tốt cho việc chia sẻ dữ liệu giữa người dùng hoặc máy.

  • DPAPI sử dụng lớp ProtectedData với phạm vi LocalMachine. Tốt cho ví dụ bảo vệ dữ liệu cấu hình trên một máy chủ bảo mật duy nhất. Nhưng bất cứ ai có thể đăng nhập vào máy đều có thể mã hóa nó, vì vậy không tốt trừ khi máy chủ được bảo mật.

  • Bất kỳ thuật toán đối xứng. Tôi thường sử dụng phương thức SymmetricAlerskym.Create () tĩnh nếu tôi không quan tâm thuật toán nào được sử dụng (thực tế nó là Rijndael theo mặc định). Trong trường hợp này, bạn cần phải bảo vệ chìa khóa của bạn bằng cách nào đó. Ví dụ, bạn có thể làm xáo trộn nó theo một cách nào đó và ẩn nó trong mã của bạn. Nhưng hãy lưu ý rằng bất kỳ ai đủ thông minh để dịch ngược mã của bạn đều có thể tìm thấy khóa.


5

Tôi muốn đăng giải pháp của mình vì không có giải pháp nào ở trên đơn giản như của tôi. Cho tôi biết bạn nghĩ gì:

 // 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)));
 }

Không bắt buộc

Điều này giả định rằng MachineKey của máy chủ được sử dụng để mã hóa giá trị giống như mã được sử dụng để giải mã giá trị. Nếu muốn, bạn có thể chỉ định MachineKey tĩnh trong Web.config để ứng dụng của bạn có thể giải mã / mã hóa dữ liệu bất kể nó chạy ở đâu (ví dụ: phát triển so với máy chủ sản xuất). Bạn có thể tạo khóa máy tĩnh theo các hướng dẫn sau .


lưu ý cách tiếp cận này chỉ có thể được sử dụng cho ứng dụng ASP.NET.
Feru

2

Không gian tên System.Security.Cryptographychứa các lớp TripleDESCryptoServiceProviderRijndaelManaged

Đừng quên thêm một tài liệu tham khảo cho System.Securityhội đồng.


8
Không phải là tôi hạ thấp, nhưng tại sao độ tuổi của một câu hỏi quan trọng khi bỏ phiếu?
user247702

2

Sử dụng TripleDESCryptoServiceProvider trong 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

Tôi đã thay đổi điều này :

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;
}

đến đây:

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

1

Sử dụng thư viện Mã hóa .Net dựng sẵn, ví dụ này cho thấy cách sử dụng Tiêu chuẩn mã hóa nâng cao (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

Tôi biết bạn nói rằng bạn không quan tâm đến mức độ an toàn của nó, nhưng nếu bạn chọn DES, bạn cũng có thể sử dụng AES, đó là phương pháp mã hóa cập nhật hơn.


0

Tôi đã sử dụng câu trả lời được chấp nhận bởi Mark Britsham và nó đã giúp tôi rất nhiều. Gần đây tôi đã phải gửi văn bản được mã hóa đến một tổ chức khác và đó là nơi phát sinh một số vấn đề. OP không yêu cầu các tùy chọn này nhưng vì đây là câu hỏi phổ biến Tôi đang đăng bài sửa đổi của mình ( Encryptvà các Decryptchức năng được mượn từ đây ):

  1. IV khác nhau cho mỗi thông báo - Ghép các byte IV với các byte mật mã trước khi lấy hex. Tất nhiên đây là một quy ước cần được chuyển đến các bên nhận được văn bản mật mã.
  2. Cho phép hai hàm tạo - một cho RijndaelManagedcác giá trị mặc định và một cho các giá trị thuộc tính có thể được chỉ định (dựa trên thỏa thuận chung giữa các bên mã hóa và giải mã)

Đây là lớp học (mẫu thử ở cuối):

/// <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

và ..

Đây là mẫu thử nghiệm:

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;
    }
}

nhập mô tả hình ảnh ở đây


-2

Tôi nghĩ rằng đây là thế giới đơn giản nhất!

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

Kiểm tra

 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? Có thật không? OP thậm chí đã gọi ROT13 như một ví dụ về những gì anh ấy không muốn làm.
dùng812786
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.