C# 加密算法

发布于 2024-11-08 23:39:38 字数 181 浏览 0 评论 0原文

互联网上有很多关于加密的答案,但我一直无法准确找到我正在寻找的内容:使用 c# 提供的工具来加密字符串和文本文件的简单强加密。

我的主要问题是我不知道如何将 IV 保存到文本文件的开头或如何创建随机 IV。我有一个关于加密流的示例,并且我已经看到了关于 DES 的示例,但是它们使用相同的 IV 和密钥,这(据我所知)不是一件好事。

There are many answers on the internet regarding encryption, but I have been unable to find exactly what I'm looking for: simple strong encryption using the tools that c# provides to encrypt strings and text files.

My main problem is that I don't know how to save the IV into the beginning of the text file or how to create a random IV. I have an example on crypto stream and I have seen an example on DES, but they use the same IV and key and that is (by what I know) not a good thing to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝戈者 2024-11-15 23:39:38

你是对的,使用相同的 IV 是一种不好的做法,特别是如果 Key 或 IV 是硬编码的。我建议使用 AesManaged 类。它使用当前标准 AES 算法。生成 IV 相当简单:

var aes = new AesManaged(); //Set your KeySize if you will generate a key too.
aes.GenerateIV();
var iv = aes.IV;

这是获取新初始化向量的简单方法。如果您的目标是加密文件,您可以存储文件,但是您将如何处理密钥呢?在应用程序中对其进行硬编码通常不是一个很好的方法。如果您的应用程序基于密码,则可以从 Rfc2898DeriveBytes 根据密码获取字节数组。这样,您的应用程序永远不知道加密密钥是什么。

下面是将 IV 写入文件,然后写入文件内容的示例。

using (AesManaged aes = new AesManaged())
{
    //Set the Key here.
    aes.GenerateIV();
    using (var transform = aes.CreateEncryptor())
    {
        using (var fileStream = new FileStream("C:\\in.txt", FileMode.Open))
        {
            using (var saveTo = new FileStream("C:\\out.txt", FileMode.Create))
            {
                using (var cryptoStream = new CryptoStream(saveTo, transform,CryptoStreamMode.Write))
                {
                    var iv = aes.IV;
                    cryptoStream.Write(iv, 0, iv.Length);
                    fileStream.CopyTo(cryptoStream);
                }
            }
        }
    }
}

You're right, using the same IV is a bad practice, especially if either the Key or IV are hard coded. I'd recommend using the AesManaged class. It uses the AES algorithm, the current standard. Generating an IV is fairly simple:

var aes = new AesManaged(); //Set your KeySize if you will generate a key too.
aes.GenerateIV();
var iv = aes.IV;

That's a simple way of getting a new initialization vector. If your goal is to encrypt a file, you can store the File, but what will you do with the Key? Hard coding it within your application is generally not a very good way of doing it. If your application will be password based, then you can generate the key from Rfc2898DeriveBytes to get a byte array based on a password. This way, your application never knows what the encryption key is.

Here is an example for writing the IV to a file, then the file contents.

using (AesManaged aes = new AesManaged())
{
    //Set the Key here.
    aes.GenerateIV();
    using (var transform = aes.CreateEncryptor())
    {
        using (var fileStream = new FileStream("C:\\in.txt", FileMode.Open))
        {
            using (var saveTo = new FileStream("C:\\out.txt", FileMode.Create))
            {
                using (var cryptoStream = new CryptoStream(saveTo, transform,CryptoStreamMode.Write))
                {
                    var iv = aes.IV;
                    cryptoStream.Write(iv, 0, iv.Length);
                    fileStream.CopyTo(cryptoStream);
                }
            }
        }
    }
}
倥絔 2024-11-15 23:39:38

请参阅以下链接中的示例,它将使用哈希、盐和 VI 密钥创建字符串加密。

https://github.com/salahuddinuk/Encryption-Decryption/ blob/master/EncryptDecrypt/Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EncryptDecrypt
{
    public partial class Form1 : Form
    {
        static readonly string PasswordHash = "P!!Sw0rd~";
        static readonly string SaltKey = "Sa~LT~KEY";
        static readonly string VIKey = "@1B2c3D4@e5F6<7H8<.";
        public Form1()
        {
            InitializeComponent();
        }

        private void btn_Process_Click(object sender, EventArgs e)
        {
            try
            {
                lbl_Error.Text = "";
                if (chb_Decrypt.Checked == true)
                    txt_Result.Text = Decrypt(txt_Value.Text);
                else
                    txt_Result.Text = Encrypt(txt_Value.Text);
            }
            catch (Exception ex)
            {
                lbl_Error.Text = ex.Message;
            }
        }
        public static string Encrypt(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
            var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));

            byte[] cipherTextBytes;

            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    cipherTextBytes = memoryStream.ToArray();
                    cryptoStream.Close();
                }
                memoryStream.Close();
            }
            return Convert.ToBase64String(cipherTextBytes);
        }
        public static string Decrypt(string encryptedText)
        {
            byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };

            var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
        }
    }
}

see the example on following link, it will create a string encryption with hash, salt and VI key.

https://github.com/salahuddinuk/Encryption-Decryption/blob/master/EncryptDecrypt/Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EncryptDecrypt
{
    public partial class Form1 : Form
    {
        static readonly string PasswordHash = "P!!Sw0rd~";
        static readonly string SaltKey = "Sa~LT~KEY";
        static readonly string VIKey = "@1B2c3D4@e5F6<7H8<.";
        public Form1()
        {
            InitializeComponent();
        }

        private void btn_Process_Click(object sender, EventArgs e)
        {
            try
            {
                lbl_Error.Text = "";
                if (chb_Decrypt.Checked == true)
                    txt_Result.Text = Decrypt(txt_Value.Text);
                else
                    txt_Result.Text = Encrypt(txt_Value.Text);
            }
            catch (Exception ex)
            {
                lbl_Error.Text = ex.Message;
            }
        }
        public static string Encrypt(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
            var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));

            byte[] cipherTextBytes;

            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    cipherTextBytes = memoryStream.ToArray();
                    cryptoStream.Close();
                }
                memoryStream.Close();
            }
            return Convert.ToBase64String(cipherTextBytes);
        }
        public static string Decrypt(string encryptedText)
        {
            byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };

            var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
        }
    }
}
朮生 2024-11-15 23:39:38

如今,AesGcm 将是一个合适的类和算法。它的示例代码很容易找到,而且它的 API 也相当简单。

要生成 IV/nonce,请使用 RandomNumberGenerator.Fill 填充正确大小的数组,对于 AES-GCM,该数组为 12 字节(96 位)。 RandomNumberGenerator 是加密安全的。

至于将 IV 写入文件,则由您决定。您正在写入文件流吗?然后开始写IV,然后继续写密文。对于 AES-GCM,我们还会编写标签,这不仅可以为我们提供加密,还可以提供经过验证的加密,即在解密时我们可以确认密文未被篡改。

当读回这样的文件时,我们分别读取每个组件 - IV、密文和标签。既然你知道如何编写它们,你就知道如何阅读它们。例如,x 字节 IV,然后是 y 字节标记,然后是剩余字节密文(如果这就是将数据写入文件的方式)。

将组件传递给 AesGcm.Decrypt 即可。

Nowadays, AesGcm would be an appropriate class and algorithm to use. Examples code for it is easy enough to find, and its API is fairly straightforward.

To generate the IV/nonce, use RandomNumberGenerator.Fill to populate an array of the correct size, which is 12 bytes (96 bits) for AES-GCM. RandomNumberGenerator is the cryptographically-secure one.

As for writing the IV to the file, that is up to you. Are you writing to a file stream? Then start by writing the IV, and then proceed to write the ciphertext. For AES-GCM, we would also write the tag, which will give us not just encryption, but authenticated encryption, i.e. on decryption we can confirm that the ciphertext has not been tampered with.

When reading such a file back in, we read each of the components separately - IV, ciphertext, and tag. Since you know how you wrote them, you know how to read them. For example, x bytes IV, then y bytes tag, then the remaining bytes ciphertext, if that is how you wrote the data to the file.

Pass the components to AesGcm.Decrypt and voila.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文