如何在c#中加密和解密字符串?


当前回答

下面是一个简单的例子,在c#中使用AES CBC模式加密字符串,并使用随机IV和HMAC和密码派生密钥,以显示基本的移动部分:

private byte[] EncryptBytes(byte[] key, byte[] plaintext)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        using (var encryptor = cipher.CreateEncryptor())
        {
            var ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);

            // IV is prepended to ciphertext
            return cipher.IV.Concat(ciphertext).ToArray();
        }
    }
}

private byte[] DecryptBytes(byte[] key, byte[] packed)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        int ivSize = cipher.BlockSize / 8;

        cipher.IV = packed.Take(ivSize).ToArray();

        using (var encryptor = cipher.CreateDecryptor())
        {
            return encryptor.TransformFinalBlock(packed, ivSize, packed.Length - ivSize);
        }
    }
}

private byte[] AddMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        var macBytes = hmac.ComputeHash(data);

        // HMAC is appended to data
        return data.Concat(macBytes).ToArray();
    }
}

private bool BadMac(byte[] found, byte[] computed)
{
    int mismatch = 0;

    // Aim for consistent timing regardless of inputs
    for (int i = 0; i < found.Length; i++)
    {
        mismatch += found[i] == computed[i] ? 0 : 1;
    }

    return mismatch != 0;
}

private byte[] RemoveMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        int macSize = hmac.HashSize / 8;

        var packed = data.Take(data.Length - macSize).ToArray();

        var foundMac = data.Skip(packed.Length).ToArray();

        var computedMac = hmac.ComputeHash(packed);

        if (this.BadMac(foundMac, computedMac))
        {
            throw new Exception("Bad MAC");
        }

        return packed;
    }            
}

private List<byte[]> DeriveTwoKeys(string password)
{
    var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    var kdf = new Rfc2898DeriveBytes(password, salt, 10000);

    var bytes = kdf.GetBytes(32); // Two keys 128 bits each

    return new List<byte[]> { bytes.Take(16).ToArray(), bytes.Skip(16).ToArray() };
}

public byte[] EncryptString(string password, String message)
{
    var keys = this.DeriveTwoKeys(password);

    var plaintext = Encoding.UTF8.GetBytes(message);

    var packed = this.EncryptBytes(keys[0], plaintext);

    return this.AddMac(keys[1], packed);
}

public String DecryptString(string password, byte[] secret)
{
    var keys = this.DeriveTwoKeys(password);

    var packed = this.RemoveMac(keys[1], secret);

    var plaintext = this.DecryptBytes(keys[0], packed);

    return Encoding.UTF8.GetString(plaintext);
}

public void Example()
{
    var password = "correcthorsebatterystaple";

    var secret = this.EncryptString(password, "Hello World");

    Console.WriteLine("secret: " + BitConverter.ToString(secret));

    var recovered = this.DecryptString(password, secret);

    Console.WriteLine(recovered);
}

其他回答

我想给你我的贡献,与我的代码AES Rfc2898DeriveBytes(这里的文档)算法,写在c#(。NET框架4),并且完全适用于有限的平台,如Windows Phone 7.0+的.NET紧凑框架(不是所有平台都支持.NET框架的每一种编码方法!)

我希望这能帮助到任何人!

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

public static class Crypto
{
    private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x0e, 0x16, 0x17 };


    public static string Encrypt(this string text, string salt)
    {
        try
        {
            using (Aes aes = new AesManaged())
            {
                Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
                aes.Key = deriveBytes.GetBytes(128 / 8);
                aes.IV = aes.Key;
                using (MemoryStream encryptionStream = new MemoryStream())
                {
                    using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        byte[] cleanText = Encoding.UTF8.GetBytes(text);
                        encrypt.Write(cleanText, 0, cleanText.Length);
                        encrypt.FlushFinalBlock();
                    }

                    byte[] encryptedData = encryptionStream.ToArray();
                    string encryptedText = Convert.ToBase64String(encryptedData);


                    return encryptedText;
                }
            }
        }
        catch
        {
            return String.Empty;
        }
    }

    public static string Decrypt(this string text, string salt)
    {
        try
        {
            using (Aes aes = new AesManaged())
            {
                Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
                aes.Key = deriveBytes.GetBytes(128 / 8);
                aes.IV = aes.Key;

                using (MemoryStream decryptionStream = new MemoryStream())
                {
                    using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        byte[] encryptedData = Convert.FromBase64String(text);


                        decrypt.Write(encryptedData, 0, encryptedData.Length);
                        decrypt.Flush();
                    }

                    byte[] decryptedData = decryptionStream.ToArray();
                    string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);


                    return decryptedText;
                }
            }
        }
        catch
        {
            return String.Empty;
        }
        }
    }
}

下面是一个使用RSA的例子。

重要:使用RSA加密KeySize - MinimumPadding加密的数据大小是有限制的。例如256字节(假设2048位密钥)- 42字节(最小OEAP填充)= 214字节(最大明文大小)

用RSA密钥替换your_rsa_key。

var provider = new System.Security.Cryptography.RSACryptoServiceProvider();
provider.ImportParameters(your_rsa_key);

var encryptedBytes = provider.Encrypt(
    System.Text.Encoding.UTF8.GetBytes("Hello World!"), true);

string decryptedTest = System.Text.Encoding.UTF8.GetString(
    provider.Decrypt(encryptedBytes, true));

更多信息,请访问MSDN - RSACryptoServiceProvider

很好的例子如何做到这一点使用PGPCore与BouncyCastle,非常简单的解决方案:https://blog.bitscry.com/2018/07/05/pgp-encryption-and-decryption-in-c/

我尝试了不同的解决方案,但这对我来说是最好的,有些bug,但这是完美的。

using (PGP pgp = new PGP())
{
// Generate keys
pgp.GenerateKey(@"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "email@email.com", "password");
// Encrypt file
pgp.EncryptFile(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted.pgp", @"C:\TEMP\keys\public.asc", true, true);
// Encrypt and sign file
pgp.EncryptFileAndSign(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "password", true, true);
// Decrypt file
pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted.pgp", @"C:\TEMP\keys\content__decrypted.txt", @"C:\TEMP\keys\private.asc", "password");
// Decrypt signed file
pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\content__decrypted_signed.txt", @"C:\TEMP\keys\private.asc", "password");

// Encrypt stream
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\keys\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\keys\content__encrypted2.pgp"))
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\keys\public.asc", FileMode.Open))
    pgp.EncryptStream(inputFileStream, outputFileStream, publicKeyStream, true, true);

// Decrypt stream
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\keys\content__encrypted2.pgp", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\keys\content__decrypted2.txt"))
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\keys\private.asc", FileMode.Open))
    pgp.DecryptStream(inputFileStream, outputFileStream, privateKeyStream, "password");
}

下面是一个简单的例子,在c#中使用AES CBC模式加密字符串,并使用随机IV和HMAC和密码派生密钥,以显示基本的移动部分:

private byte[] EncryptBytes(byte[] key, byte[] plaintext)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        using (var encryptor = cipher.CreateEncryptor())
        {
            var ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);

            // IV is prepended to ciphertext
            return cipher.IV.Concat(ciphertext).ToArray();
        }
    }
}

private byte[] DecryptBytes(byte[] key, byte[] packed)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        int ivSize = cipher.BlockSize / 8;

        cipher.IV = packed.Take(ivSize).ToArray();

        using (var encryptor = cipher.CreateDecryptor())
        {
            return encryptor.TransformFinalBlock(packed, ivSize, packed.Length - ivSize);
        }
    }
}

private byte[] AddMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        var macBytes = hmac.ComputeHash(data);

        // HMAC is appended to data
        return data.Concat(macBytes).ToArray();
    }
}

private bool BadMac(byte[] found, byte[] computed)
{
    int mismatch = 0;

    // Aim for consistent timing regardless of inputs
    for (int i = 0; i < found.Length; i++)
    {
        mismatch += found[i] == computed[i] ? 0 : 1;
    }

    return mismatch != 0;
}

private byte[] RemoveMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        int macSize = hmac.HashSize / 8;

        var packed = data.Take(data.Length - macSize).ToArray();

        var foundMac = data.Skip(packed.Length).ToArray();

        var computedMac = hmac.ComputeHash(packed);

        if (this.BadMac(foundMac, computedMac))
        {
            throw new Exception("Bad MAC");
        }

        return packed;
    }            
}

private List<byte[]> DeriveTwoKeys(string password)
{
    var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    var kdf = new Rfc2898DeriveBytes(password, salt, 10000);

    var bytes = kdf.GetBytes(32); // Two keys 128 bits each

    return new List<byte[]> { bytes.Take(16).ToArray(), bytes.Skip(16).ToArray() };
}

public byte[] EncryptString(string password, String message)
{
    var keys = this.DeriveTwoKeys(password);

    var plaintext = Encoding.UTF8.GetBytes(message);

    var packed = this.EncryptBytes(keys[0], plaintext);

    return this.AddMac(keys[1], packed);
}

public String DecryptString(string password, byte[] secret)
{
    var keys = this.DeriveTwoKeys(password);

    var packed = this.RemoveMac(keys[1], secret);

    var plaintext = this.DecryptBytes(keys[0], packed);

    return Encoding.UTF8.GetString(plaintext);
}

public void Example()
{
    var password = "correcthorsebatterystaple";

    var secret = this.EncryptString(password, "Hello World");

    Console.WriteLine("secret: " + BitConverter.ToString(secret));

    var recovered = this.DecryptString(password, secret);

    Console.WriteLine(recovered);
}

加密是编程中非常常见的问题。我认为最好是安装一个包来为您做这个任务。也许是一个简单的开源NuGet项目 简单Aes加密

密钥在配置文件中,因此很容易在生产环境中更改,而且我没有看到任何缺点。

<MessageEncryption>
  <EncryptionKey KeySize="256" Key="3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+796tvu8="/>
</MessageEncryption>