ข้อมูลสองทางที่ไม่ปลอดภัยง่าย“ ทำให้งงงวย” หรือไม่?


426

ฉันกำลังมองหาฟังก์ชั่น obfuscation ที่ง่ายมาก (เช่นเข้ารหัสและถอดรหัส แต่ไม่จำเป็นต้องปลอดภัย) สำหรับข้อมูลบางอย่าง มันไม่ใช่ภารกิจที่สำคัญ ฉันต้องการบางสิ่งบางอย่างในการรักษาคนที่ซื่อสัตย์ แต่สิ่งที่แข็งแกร่งกว่าROT13หรือBase64เล็กน้อย

ฉันต้องการบางสิ่งที่รวมอยู่ใน. NET Framework 2.0 แล้วดังนั้นฉันไม่ต้องกังวลกับการพึ่งพาภายนอกใด ๆ

ฉันไม่ต้องการยุ่งกับกุญแจสาธารณะ / ส่วนตัว ฯลฯ ฉันไม่รู้เกี่ยวกับการเข้ารหัส แต่ฉันรู้พอที่จะรู้ว่าสิ่งที่ฉันเขียนจะน้อยกว่าไร้ค่า ... อันที่จริงแล้ว ฉันอาจทำให้คณิตศาสตร์ผิดพลาดและทำให้แตกได้เล็กน้อย


3
สวัสดีมาร์ค - ไม่มีปัญหา ฉันรู้สึกไม่ดีที่ฉันต้องยอมรับคำตอบจาก richdiet เนื่องจากฉันใช้วิธีการแก้ปัญหาของเขาจริง ๆ และมันก็ใช้ได้ดี อย่างไรก็ตามฉันกลับมาที่นี่อีกครั้งเพื่ออ่านคำตอบอื่น ๆ และคุณดีกว่าจริงๆ ไม่มีเหตุผลที่จะบอกให้คนอื่นใช้บางสิ่งบางอย่างในขณะที่ใช้งานได้จริง ๆ ไม่ใช่วิธีที่ยอดเยี่ยมในการทำบางสิ่งบางอย่างเมื่อมีคำตอบที่ดีกว่า
Matt Dawdy

3
ประหยัดเวลาด้วยตัวคุณเองและใช้ HttpServerUtility.UrlTokenEn / Decode เพื่อแปลงไปมาระหว่างอาร์เรย์ไบต์เป็นสตริงที่เป็นมิตรต่อ url
Praesagus

32
+1 สำหรับการไม่พยายามม้วนการออกแบบที่ฉลาดของคุณเอง คุณอาจไม่รู้เรื่องการเข้ารหัสมากนัก แต่ความจริงที่ว่าคุณรู้ว่าสิ่งนี้ทำให้คุณอยู่ข้างหน้านักพัฒนาส่วนใหญ่ฉันได้พบกับผู้ที่ไม่ค่อยรู้เรื่องการเข้ารหัส แต่คิดว่าพวกเขาสามารถสร้างโซลูชันของตัวเองได้
Dinah

6
ข้อควรระวัง: คำตอบจำนวนมากในคำถามนี้เป็นการเข้ารหัสที่ไม่ผ่านการตรวจสอบสิทธิ์เท่านั้น ซึ่งหมายความว่าผู้โจมตีสามารถเปลี่ยนแปลงข้อมูลได้โดยไม่ต้องแจ้งให้แอปทราบ มันนำไปสู่ช่องโหว่ที่ร้ายแรงอื่น ๆ เช่นกัน (เช่นการถอดรหัสโดยไม่มีกุญแจเนื่องจากช่องว่างภายใน) TL; DR: อย่าใช้รหัสในคำตอบที่ให้ถ้าคุณไม่ตกลงกับสิ่งนั้นหรือไม่เข้าใจสิ่งที่ฉันเพิ่งพูดไป
usr

36
ไม่ใช่คำตอบเดียวสำหรับคำถามนี้ที่อธิบายถึงการเข้ารหัสที่ปลอดภัย ใช้คำตอบของ jbtule ที่Encrypt และถอดรหัสสตริงแทน
CodesInChaos

คำตอบ:


471

คำตอบอื่น ๆ ที่นี่ใช้ได้ดี แต่ AES เป็นอัลกอริทึมการเข้ารหัสที่ปลอดภัยและทันสมัย นี่เป็นคลาสที่ฉันได้รับเมื่อไม่กี่ปีที่ผ่านมาเพื่อทำการเข้ารหัส AES ที่ฉันได้แก้ไขเมื่อเวลาผ่านไปเพื่อให้เป็นมิตรกับเว็บแอปพลิเคชัน (e, g. ฉันได้สร้างวิธีการเข้ารหัส / ถอดรหัสที่ทำงานกับสตริงที่เป็นมิตรกับ URL) นอกจากนี้ยังมีวิธีการที่ทำงานกับอาร์เรย์ไบต์

หมายเหตุ: คุณควรใช้ค่าที่แตกต่างกันในคีย์ (32 ไบต์) และอาร์เรย์เวกเตอร์ (16 ไบต์)! คุณไม่ต้องการให้ใครรู้คีย์ของคุณเพียงแค่สมมติว่าคุณใช้รหัสนี้ตามที่เป็นอยู่! สิ่งที่คุณต้องทำคือเปลี่ยนตัวเลขบางส่วน (ต้องเป็น <= 255) ในอาร์เรย์ Key และ Vector (ฉันทิ้งค่าที่ไม่ถูกต้องไว้ในอาร์เรย์ Vector เพื่อให้แน่ใจว่าคุณทำเช่นนี้ ... ) คุณสามารถใช้https://www.random.org/bytes/เพื่อสร้างชุดใหม่ได้อย่างง่ายดาย:

ใช้ง่าย: เพียงยกตัวอย่างคลาสแล้วเรียก (ปกติ) EncryptToString (สตริง StringToEncrypt) และ DecryptString (สตริง StringToDecrypt) เป็นวิธีการ มันจะไม่ง่ายกว่านี้ (หรือปลอดภัยกว่า) เมื่อคุณมีชั้นเรียนนี้แล้ว


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 - เสร็จแล้วโดยมีวัตถุประสงค์เพื่อให้คุณเปลี่ยนค่าในอาร์เรย์เป็น Mark บันทึกในวรรคสอง
Pauk

42
คุณไม่ควรใช้ IV เช่นนี้ สำหรับข้อความสองข้อความที่ระบุไม่ควรเข้ารหัสด้วย Key เดียวกันและ IV เดียวกัน IV ควรเป็นแบบสุ่มสำหรับแต่ละข้อความต่อท้าย cryptostream และอ่านก่อนที่จะถอดรหัส crypto.stackexchange.com/a/82/1934
jbtule

30
การใช้ IV แบบสุ่มสำหรับแต่ละข้อความไม่ใช่สิ่งแปลกใหม่หรือใหม่เพียงสำคัญและเป็นส่วนหนึ่งของการออกแบบอัลกอริทึม การใช้ IV ที่สามารถคาดการณ์ได้สำหรับทุกข้อความเป็นความผิดพลาดของการเข้ารหัสลับทั่วไปที่ไม่จำเป็นต้องต่อเนื่อง
jbtule

14
โปรดทราบว่าผลที่ตามมาจากการใช้ CBC เป็นโหมดของมันคือคุณมีแนวโน้มที่จะเสี่ยงต่อการโจมตีของช่องว่างภายใน ใช้การตรวจสอบสิทธิ์การเข้ารหัสและเมื่อใดก็ตามที่เป็นไปได้ไม่ใช้การเข้ารหัสด้วยตัวคุณเอง
Stephen Touset

57
คำเตือนเกี่ยวกับความปลอดภัย: อย่าใช้รหัสนี้แม้จะเป็นคำตอบที่ยอมรับได้แล้วก็ตาม แต่ก็ยังมีปัญหาด้านความปลอดภัยที่กล่าวถึงในความคิดเห็นข้างต้นที่ผู้เขียนยังคงเพิกเฉยต่อเรื่องนี้เป็นเวลา 8 ปี
jbtule

176

ฉันทำความสะอาด SimpleAES (ด้านบน) เพื่อการใช้งานของฉัน แก้ไขวิธีการเข้ารหัส / ถอดรหัสที่ซับซ้อน; วิธีการแยกกันสำหรับการเข้ารหัสบัฟเฟอร์ไบต์สตริงและสตริงที่เป็นมิตรกับ URL; ใช้ประโยชน์จากห้องสมุดที่มีอยู่สำหรับการเข้ารหัส URL

รหัสมีขนาดเล็กเรียบง่ายเร็วขึ้นและมีความกระชับมากขึ้น ตัวอย่างเช่นjohnsmith@gmail.comสร้าง:

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

รหัส:

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
เมื่อถอดรหัสฉันต้องแทนที่ช่องว่างด้วย + เพื่อให้ทำงานกับ QueryString ใน Chrome: (ใหม่ SimplerAES ()) ถอดรหัส (Request.QueryString ["myParam"]) แทนที่ ('', '+'));
รักสด

20
อย่าใช้ Vector เริ่มต้นคงที่ดูที่: crypto.stackexchange.com/questions/66/…สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุ แต่ให้สร้าง IV ใหม่สำหรับการเข้ารหัสแต่ละรายการและต่อท้าย cryptotext นั้นดีขึ้นมากและไม่ยาก
Tom Heard

2
โปรดทราบว่าผลลัพธ์ของวิธี EncryptToUrl ในโซลูชันนี้ (หรือการใช้สตริง UrlEncoded พื้นฐาน 64 โดยทั่วไป) จะไม่ทำงานตามค่าเริ่มต้นภายใต้ IIS 7 เมื่อใช้เป็นส่วนหนึ่งของเส้นทาง URL (ไม่ใช่สตริงแบบสอบถาม) เช่นใน เส้นทาง ASP.NET MVC เนื่องจากการตั้งค่าความปลอดภัย IIS 7 สำหรับข้อมูลเพิ่มเติมโปรดดู: stackoverflow.com/a/2014121/12484
Jon Schneider

5
@ TomHeard วิธีการอย่างใดอย่างหนึ่งเกี่ยวกับการทำที่มีรหัสข้างต้น?
MKII

26
คำเตือนความปลอดภัย: อย่าใช้รหัสนี้ดูความคิดเห็นโดย @TomHeard
jbtule

36

ใช่เพิ่มSystem.Securityชุดประกอบนำเข้าSystem.Security.Cryptographyเนมสเปซ นี่คือตัวอย่างง่ายๆของการเข้ารหัสอัลกอริทึมแบบสมมาตร (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
นี่เป็นการเข้ารหัสสองทางที่ดีและกะทัดรัด ข้อแม้เดียวคือ DES นั้นไม่ถือว่าความปลอดภัยล้ำสมัยอีกต่อไป ตอนนี้ชื่อนั้นไปที่อัลกอริทึม AES ที่ฉันพูดถึงด้านล่าง
Mark Brittingham

@richdiet ฉันขอโทษฉันไม่ยอมรับคำตอบของคุณ คำตอบอื่น ๆ ที่มี 37 คะแนนโหวตเพราะมันเป็นปัจจุบันมากกว่า ขอบคุณสำหรับคำตอบเพราะยังดีอยู่
Matt Dawdy

14
@ MarkBrittingham: รหัสบล็อกใด ๆ ที่ไม่มีฟังก์ชั่นการผูกมัดบล็อกเวกเตอร์ initialisation และการเติมที่เหมาะสมนั้นไม่ปลอดภัย การใช้ DES เป็นปัญหาที่สำคัญน้อยที่สุดสำหรับโครงร่างนี้
Hubert Kario

2
ดังนั้นกุญแจอยู่ที่ไหน?
อเล็กซ์

22
คำเตือนความปลอดภัย: อย่าใช้รหัสนี้ดูความคิดเห็นโดย @HubertKario
jbtule

28

แค่คิดว่าฉันจะเพิ่มว่าฉันได้ปรับปรุง SimplerAES ของ Mud โดยการเพิ่ม IV แบบสุ่มที่ส่งกลับภายในสตริงการเข้ารหัส สิ่งนี้จะช่วยปรับปรุงการเข้ารหัสเมื่อการเข้ารหัสสตริงเดียวกันจะส่งผลให้เกิดผลลัพธ์ที่แตกต่างกันในแต่ละครั้ง

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

และทดสอบหน่วยโบนัส

[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) อย่าใช้System.Randomเป็น RNG 2) สิ่งนี้ถูกทำลายอย่างสิ้นเชิงจากการโจมตีแบบ
เข้ารหัส

21
คำเตือนด้านความปลอดภัย: อย่าใช้รหัสนี้ดูความคิดเห็นด้านบนโดย @CodesInChaos
jbtule

@ jbtule โปรดอย่าเข้าใจผิดกับทุกคนที่ไม่ต้องการให้เกิดความยุ่งยากเพียงแค่เข้ารหัสและผู้ที่ไม่ระวังเกี่ยวกับการโจมตี - โปรดอย่าสั่งถ้าคุณต้องการให้คำแนะนำ
Virbhadrasinh

@Virbhadrasinh ไม่มีส่วนใดที่เข้าใจผิดในความจริงแล้วมันค่อนข้างตรงกันข้าม หากคุณกำลังจะใช้ AES การใช้สิ่งที่ถูกต้องเป็นสิ่งสำคัญมากการใช้อย่างไม่ถูกต้องและบอกว่าไม่เป็นไรฉันไม่ได้ใช้สิ่งที่สำคัญถูกเข้าใจผิด
jbtule

1
@Corey ไม่ตะโกนและปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดในการจัดการกับปัญหาด้านความปลอดภัยในคำตอบสแต็คล้น หากคุณต้องการลิงค์มันถูกโพสต์ในความคิดเห็นคำถาม แต่ฉันจะใส่ไว้ที่นี่เพื่อคุณเช่นกันstackoverflow.com/a/10366194/637783
jbtule

12

คำตอบที่แตกต่างของ Marks (ยอดเยี่ยม)

  • เพิ่ม "using" s
  • ทำให้คลาส IDisposable
  • ลบรหัสการเข้ารหัส URL เพื่อทำให้ตัวอย่างง่ายขึ้น
  • เพิ่มฟิกซ์เจอร์ทดสอบอย่างง่ายเพื่อสาธิตการใช้งาน

หวังว่านี่จะช่วยได้

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

คำตอบที่ดี. สิ่งหนึ่งในวิธีการกำจัดคุณจะต้องส่ง rijndael ไปยัง IDisposable หรือคุณจะได้รับข้อผิดพลาดในระดับการป้องกันโดยการโทรหา Dispose
John ClearZ

8
อย่าใช้ Vector เริ่มต้นคงที่ดูที่: crypto.stackexchange.com/questions/66/…สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุ แต่ให้สร้าง IV ใหม่สำหรับการเข้ารหัสแต่ละรายการและต่อท้าย cryptotext นั้นดีขึ้นมากและไม่ยาก
Tom Heard

5
@Chalky ในการเข้ารหัสคุณใช้คลาส Rijndael เพื่อสร้าง IV แบบสุ่มสำหรับคุณ ( msdn.microsoft.com/en-us/library/… ) ทำการเข้ารหัสของคุณแล้วหยิบ IV จากอินสแตนซ์ Rijndael โดยใช้คุณสมบัติ IV . จากนั้นคุณเติม (หรือต่อท้ายทำงานได้ตราบใดที่ถอดรหัสของคุณคว้ามันจากด้านเดียวกัน) ไปยังข้อความ crypto ของคุณ เมื่อถอดรหัสคุณดึง IV จากข้อมูลที่ได้รับ (ขนาดของคุณสมบัติ IV เหมือนกับคุณสมบัติ BlockSize หารด้วย 8) จากนั้นส่งผ่านไปยังอินสแตนซ์ถอดรหัสของคุณก่อนถอดรหัส
Tom Heard

2
@Chalky โปรดทราบว่า IV ไม่จำเป็นต้องเป็นความลับ แต่จะต้องไม่ซ้ำกันสำหรับแต่ละข้อความที่ส่ง
Tom Heard

20
คำเตือนความปลอดภัย: อย่าใช้รหัสนี้ดูความคิดเห็นข้างบนโดย @TomHeard
jbtule

8

[แก้ไข] ปีต่อมาฉันกลับมาพูดว่า: อย่าทำอย่างนี้! ดูว่ามีอะไรผิดปกติกับการเข้ารหัส XOR สำหรับรายละเอียด

การเข้ารหัสสองทางที่ง่ายและง่ายมากคือการเข้ารหัส XOR

  1. ขึ้นมาด้วยรหัสผ่าน Let 's mypassได้ว่าจะเป็น
  2. แปลงรหัสผ่านเป็นไบนารี (ตาม ASCII) รหัสผ่านจะกลายเป็น 01101101 01111001 01110000 01100001 01110011 01110011
  3. นำข้อความที่คุณต้องการเข้ารหัส แปลงมันเป็นไบนารี่ด้วย
  4. ดูที่ความยาวของข้อความ หากความยาวข้อความคือ 400 ไบต์ให้เปลี่ยนรหัสผ่านเป็นสตริงไบต์ 400 โดยทำซ้ำซ้ำแล้วซ้ำอีก มันจะกลายเป็น 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 0111001 01110011 01110011 0101001 0111001 0111001 01110011 01110011 01110011 ... (หรือmypassmypassmypass...)
  5. แฮคเกอร์ข้อความด้วยรหัสผ่านแบบยาว
  6. ส่งผล
  7. อีกครั้ง XOR ข้อความเข้ารหัสด้วยรหัสผ่านเดียวกัน ( mypassmypassmypass...)
  8. มีข้อความของคุณ!

10
@Ryan ไม่ใช่ทุกสถานการณ์ที่ต้องการแฮ็ชที่เข้ารหัสลับหรือ Rijndael ciphers "การเข้ารหัสแบบสองทางแบบง่าย" อาจหมายถึงความเรียบง่ายซึ่งแนะนำ xor หรือแม้กระทั่ง ROT13

1
@Ryan: AES พร้อมคีย์การเข้ารหัสแบบคงที่ไม่มีเวกเตอร์การเริ่มต้นและไม่มีฟังก์ชั่นการบล็อกการเชื่อมโยงเป็นเพียงชื่อแฟนซีสำหรับการเข้ารหัส XOR คุณเพียงแค่ใช้ KDF แฟนซีจริงๆ ...
Hubert Kario

17
คำเตือนด้านความปลอดภัย: อย่าใช้รหัสนี้การเข้ารหัส XOR ด้วยรหัสซ้ำจะแตกเล็กน้อย
jbtule

7

ฉันรวมสิ่งที่ฉันพบว่าดีที่สุดจากคำตอบและความคิดเห็นต่างๆ

  • เวกเตอร์เริ่มต้นแบบสุ่มนำเสนอต่อข้อความ crypto (@jbtule)
  • ใช้ TransformFinalBlock () แทน MemoryStream (@RenniePet)
  • ไม่มีคีย์ที่เติมไว้ล่วงหน้าเพื่อหลีกเลี่ยงการคัดลอกและวางความเสียหาย
  • ทิ้งและใช้รูปแบบที่เหมาะสม

รหัส:

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

อัปเดต 2015-07-18: แก้ไขข้อผิดพลาดในวิธีการเข้ารหัสแบบส่วนตัว () โดยความคิดเห็นของ @bpsilver และ @Evereq IV ถูกเข้ารหัสโดยไม่ตั้งใจขณะนี้ได้รับการเติมข้อความที่ชัดเจนตามที่คาดการณ์ไว้โดย Decrypt ()


คุณควรเข้ารหัส inputBuffer ทั้งหมดด้วย IV ที่เติมไว้มิฉะนั้นอักขระ 16 ตัวแรกของการเข้ารหัสแบบสตริงจะหายไป ดังนั้นรหัสของคุณควรอ่าน:return _encryptor.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
bpsilver

2
ในกรณีนี้:byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); return _rijndael.IV.Concat(inputBuffer).ToArray();
bpsilver

1
นั่นจะทำสิ่งเดียวกันกับการใช้งานในปัจจุบันใช่มั้ย
angularsen

1
"เติม ME 16, 24 หรือ 32 CHARS" ให้ดีไม่ใช่ไม่ใช่ก่อนการถอดรหัส 64 และที่สำคัญควรเป็นแบบสุ่ม สุ่มจริงๆ
Maarten Bodewes

1
ฉันสังเกตเห็นว่า @bpsilver ถูกต้องและรหัสที่ให้ไว้จะไม่ทำงานหากไม่มีการแก้ไขของเขา: วิธีการเข้ารหัสจะส่งคืนข้อมูลที่เข้ารหัสโดยไม่มี IV (ก่อนอื่นจะเพิ่ม IV ในอินพุตอินพุต แต่จะเข้ารหัสและส่งคืนข้อมูลโดยไม่ต้อง) ดังนั้นถ้าเป็นไปได้เพียงแค่อัพเดตคำตอบด้วยรหัสของเขา (หมายเหตุ: ฉันทดสอบเฉพาะวิธีการที่มีพารามิเตอร์ไบต์ [] ไม่ใช่สตริง) ขอบคุณ!
Evereq

6

หากคุณต้องการการเข้ารหัสอย่างง่าย (เช่นอาจเป็นไปได้ที่แครกเกอร์ที่กำหนดจะแตก แต่ปิดกั้นผู้ใช้ทั่วไป) ให้เลือกวลีรหัสผ่านที่มีความยาวเท่ากันสองคำพูด:

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

และ xor ข้อมูลของคุณกับทั้งสองของพวกเขา (บ่วงวลีรหัสผ่านถ้าจำเป็น) (ก) ตัวอย่างเช่น:

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

ใครบางคนที่ค้นหาไบนารีของคุณอาจคิดว่าสาย DNA เป็นกุญแจสำคัญ แต่พวกเขาไม่คิดว่ารหัส C คือสิ่งอื่นใดนอกจากหน่วยความจำที่ไม่ได้เตรียมการบันทึกไว้ด้วยไบนารีของคุณ


(a)โปรดจำไว้ว่านี่เป็นการเข้ารหัสที่ง่ายมากและบางครั้งอาจไม่ได้รับการพิจารณาการเข้ารหัส (เนื่องจากเจตนาของการเข้ารหัสคือเพื่อป้องกันการเข้าถึงโดยไม่ได้รับอนุญาตแทนที่จะทำให้ยากขึ้น) แม้ว่าแน่นอนว่าการเข้ารหัสที่แข็งแกร่งที่สุดยังไม่ปลอดภัยเมื่อมีใครบางคนยืนอยู่เหนือผู้ถือกุญแจด้วยท่อเหล็ก

ตามที่ระบุไว้ในประโยคแรกนี่เป็นวิธีที่ทำให้ยากสำหรับผู้โจมตีทั่วไปที่พวกเขาจะเดินหน้าต่อไป มันคล้ายกับการป้องกันการย่องเบาที่บ้านของคุณ - คุณไม่จำเป็นต้องทำให้มันเข้มแข็งคุณเพียงแค่ต้องทำให้หญิงตั้งครรภ์น้อยกว่าบ้านข้างๆ :-)


3
ความคิดที่น่าสนใจ ฉันไม่แน่ใจว่าฉันจะ "เชื่อ" ซอร์สโค้ดในไบนารี - แต่วิธีการปรับความคิดที่จะใช้ข้อความแสดงข้อผิดพลาดเป็นวลีรหัสผ่าน?
Jon Skeet

1
ฉันชอบที่จะใช้ md5 hash ของสตริง cleartext ที่มีอยู่แล้วในแอปพลิเคชัน (ข้อความแสดงข้อผิดพลาดหรือมากกว่านั้น)
Treb

2
ทำไมพวกเขาต้องมีความยาวเท่ากัน? จริงๆแล้วมันดูดีกว่าถ้ามันมีความยาวต่างกัน ด้วยวิธีนี้ความยาวของตัวถูกดำเนินการ XOR ที่มีประสิทธิภาพของคุณคือ LCM (length1, length2) แทนที่จะเป็นแค่ length1 (= length2) ซึ่งแน่นอนจะกลายเป็น length1 * length2 ถ้าความยาวค่อนข้างสำคัญ
Fantius

15
คำเตือนด้านความปลอดภัย: อย่าใช้รหัสนี้คีย์การทำซ้ำ XOR สามารถถอดรหัสได้ง่ายโดยมีความรู้ทั่วไปเกี่ยวกับข้อมูลที่เข้ารหัส
jbtule

3
@jbtule หากคุณอ่านคำถามคุณจะรู้ว่าการเข้ารหัสที่ปลอดภัยยิ่งขึ้นนั้นไม่จำเป็นต้องใช้ โดยเฉพาะการอ้างอิงถึง 'การเข้ารหัสอย่างง่าย', 'ไม่ได้เป็นภารกิจที่สำคัญ' และ 'รักษาความซื่อสัตย์ของคนซื่อสัตย์' คุณควรอ่านย่อหน้าแรกของฉันซึ่งเรียกความจริงว่ามันจะไม่ล็อคผู้โจมตีที่กำหนด
paxdiablo

5

การเข้ารหัสนั้นง่าย: ตามที่คนอื่น ๆ ชี้ให้เห็นมีคลาสในเนมสเปซ System.Security.Cryptography ที่ทำงานทั้งหมดให้คุณ ใช้พวกเขามากกว่าโซลูชันที่ปลูกเองที่บ้าน

แต่การถอดรหัสก็ง่ายเช่นกัน ปัญหาที่คุณมีไม่ใช่อัลกอริธึมการเข้ารหัส แต่เป็นการป้องกันการเข้าถึงคีย์ที่ใช้สำหรับการถอดรหัส

ฉันจะใช้หนึ่งในวิธีแก้ไขปัญหาต่อไปนี้:

  • DPAPI โดยใช้คลาส ProtectedData พร้อมขอบเขต CurrentUser นี่เป็นเรื่องง่ายเพราะคุณไม่ต้องกังวลกับกุญแจ ข้อมูลสามารถถอดรหัสได้โดยผู้ใช้รายเดียวกันดังนั้นจึงไม่ดีสำหรับการแบ่งปันข้อมูลระหว่างผู้ใช้หรือเครื่อง

  • DPAPI โดยใช้คลาส ProtectedData พร้อมขอบเขต LocalMachine เหมาะสำหรับการปกป้องข้อมูลการกำหนดค่าบนเซิร์ฟเวอร์ที่ปลอดภัยเพียงเครื่องเดียว แต่ทุกคนที่สามารถเข้าสู่เครื่องสามารถเข้ารหัสได้ดังนั้นจึงไม่ดีเว้นแต่เซิร์ฟเวอร์จะปลอดภัย

  • อัลกอริทึมแบบสมมาตรใด ๆ ฉันมักจะใช้วิธี SymmetricAlgorithm.Create () แบบคงที่หากฉันไม่สนใจว่าจะใช้อัลกอริทึมใด (อันที่จริงแล้วมันเป็น Rijndael ตามค่าเริ่มต้น) ในกรณีนี้คุณต้องปกป้องกุญแจของคุณอย่างใด เช่นคุณสามารถทำให้งงงวยในบางวิธีและซ่อนไว้ในรหัสของคุณ แต่ระวังให้ดีว่าใครก็ตามที่ฉลาดพอที่จะถอดรหัสรหัสของคุณจะสามารถค้นพบกุญแจได้


5

ฉันต้องการโพสต์โซลูชันของฉันเนื่องจากไม่มีวิธีการข้างต้นที่ง่ายเหมือนของฉัน แจ้งให้เราทราบสิ่งที่คุณคิด:

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

ไม่จำเป็น

สมมติว่า MachineKey ของเซิร์ฟเวอร์ที่ใช้ในการเข้ารหัสค่านั้นเหมือนกับที่ใช้ในการถอดรหัสค่า หากต้องการคุณสามารถระบุ MachineKey แบบคงที่ใน Web.config เพื่อให้แอปพลิเคชันของคุณสามารถถอดรหัส / เข้ารหัสข้อมูลได้ไม่ว่าจะทำงานอยู่ที่ไหน (เช่นการพัฒนากับเซิร์ฟเวอร์ที่ใช้งานจริง) คุณสามารถสร้างคีย์เครื่องคงทำตามคำแนะนำเหล่านี้


โปรดทราบว่าวิธีการนี้สามารถใช้ได้กับแอป ASP.NET เท่านั้น
Feru

2

เนมสเปซSystem.Security.CryptographyมีTripleDESCryptoServiceProviderและRijndaelManagedคลาส

อย่าลืมเพิ่มการอ้างอิงไปยังSystem.Securityแอสเซมบลี


8
ไม่ใช่ว่าฉันลงคะแนน แต่ทำไมอายุของคำถามจึงมีความสำคัญเมื่อลงคะแนน
user247702

2

การใช้ TripleDESCryptoServiceProvider ใน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

ฉันเปลี่ยนสิ่งนี้ :

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

สำหรับสิ่งนี้:

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

1

การใช้ไลบรารีการเข้ารหัส. net ในตัวตัวอย่างนี้จะแสดงวิธีใช้มาตรฐานการเข้ารหัสขั้นสูง (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

ฉันรู้ว่าคุณบอกว่าคุณไม่สนใจว่ามันจะปลอดภัยแค่ไหน แต่ถ้าคุณเลือกDESคุณก็อาจใช้AESเป็นวิธีการเข้ารหัสที่ทันสมัยยิ่งขึ้น


0

ฉันใช้คำตอบที่ยอมรับโดยMark Brittinghamและมันช่วยฉันได้มาก เมื่อเร็ว ๆ นี้ฉันต้องส่งข้อความที่เข้ารหัสไปยังองค์กรอื่นและนั่นเป็นปัญหาที่เกิดขึ้น OP ไม่ต้องการตัวเลือกเหล่านี้ แต่เนื่องจากเป็นคำถามยอดนิยมที่ฉันโพสต์การแก้ไขของฉัน ( EncryptและDecryptฟังก์ชันที่ยืมมาจากที่นี่ ):

  1. IV ที่แตกต่างกันสำหรับทุกข้อความ - เชื่อมต่อ IV ไบต์กับไบต์ตัวเลขก่อนที่จะได้ hex ของหลักสูตรนี้เป็นแบบแผนที่จำเป็นต้องถ่ายทอดไปยังฝ่ายที่ได้รับข้อความตัวเลข
  2. อนุญาตให้ผู้สร้างสองคน - หนึ่งสำหรับค่าเริ่มต้นRijndaelManagedและหนึ่งที่สามารถระบุค่าคุณสมบัติ (ขึ้นอยู่กับข้อตกลงร่วมกันระหว่างการเข้ารหัสและถอดรหัสปาร์ตี้)

นี่คือคลาส (ตัวอย่างทดสอบท้าย):

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

และ..

นี่คือตัวอย่างทดสอบ:

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

ป้อนคำอธิบายรูปภาพที่นี่


-2

ฉันคิดว่านี่เป็นโลกที่ง่ายที่สุด!

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

ทดสอบ

 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? จริงๆ? OP เรียก ROT13 ออกมาเป็นตัวอย่างของสิ่งที่เขาไม่ต้องการทำ
user812786
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.