在C#中加密和解密字符串[重复]

 2023-09-05 阅读 89 评论 0

摘要:本文翻译自:Encrypting & Decrypting a String in C# [duplicate] This question already has an answer here: 这个问题在这里已有答案: Encrypt and decrypt a string in C#? 在C#中加密和解密字符串? 28 answers 28个答案 What is the mos

本文翻译自:Encrypting & Decrypting a String in C# [duplicate]

This question already has an answer here: 这个问题在这里已有答案:

  • Encrypt and decrypt a string in C#? 在C#中加密和解密字符串? 28 answers 28个答案

What is the most modern (best) way of satisfying the following in C#? 在C#中满足以下内容的最现代(最佳)方式是什么?

string encryptedString = SomeStaticClass.Encrypt(sourceString);string decryptedString = SomeStaticClass.Decrypt(encryptedString);

BUT with a minimum of fuss involving salts, keys, mucking about with byte[], etc. 但最小的涉及盐,键,与字节[]等混乱的大惊小怪等。

Been Googling and confused at what I'm finding (you can see the list of similar SO Qs to see this is a deceptive question to ask). 谷歌搜索和混淆我发现的东西(你可以看到类似的SO Q列表,看这是一个欺骗性的问题)。


#1楼

参考:https://stackoom.com/question/gfDs/在C-中加密和解密字符串-重复


#2楼

您可能正在寻找ProtectedData类,它使用用户的登录凭据加密数据。


#3楼

The easiest way that I've seen to do encryption is through RSA 我看到加密的最简单方法是通过RSA

Check out the MSDN on it: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx 查看MSDN: http : //msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx

It does involve using bytes, but when it comes down to it you kind of do want encryption and decryption to be tough to figure out otherwise it will be easy to hack. 它确实涉及使用字节,但当它归结为它时,你确实希望加密和解密很难弄清楚,否则它很容易被破解。


#4楼

If you need to store a password in memory and would like to have it encrypted you should use SecureString : 如果您需要在内存中存储密码并希望加密,则应使用SecureString

http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx

For more general uses I would use a FIPS approved algorithm such as Advanced Encryption Standard, formerly known as Rijndael. 对于更一般的用途,我会使用FIPS认可的算法,例如Advanced Encryption Standard,以前称为Rijndael。 See this page for an implementation example: 有关实现示例,请参阅此页面:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx


#5楼

Try this class: 试试这堂课:

public class DataEncryptor
{TripleDESCryptoServiceProvider symm;#region Factorypublic DataEncryptor(){this.symm = new TripleDESCryptoServiceProvider();this.symm.Padding = PaddingMode.PKCS7;}public DataEncryptor(TripleDESCryptoServiceProvider keys){this.symm = keys;}public DataEncryptor(byte[] key, byte[] iv){this.symm = new TripleDESCryptoServiceProvider();this.symm.Padding = PaddingMode.PKCS7;this.symm.Key = key;this.symm.IV = iv;}#endregion#region Propertiespublic TripleDESCryptoServiceProvider Algorithm{get { return symm; }set { symm = value; }}public byte[] Key{get { return symm.Key; }set { symm.Key = value; }}public byte[] IV{get { return symm.IV; }set { symm.IV = value; }}#endregion#region Cryptopublic byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }public byte[] Encrypt(byte[] data, int length){try{// Create a MemoryStream.var ms = new MemoryStream();// Create a CryptoStream using the MemoryStream // and the passed key and initialization vector (IV).var cs = new CryptoStream(ms,symm.CreateEncryptor(symm.Key, symm.IV),CryptoStreamMode.Write);// Write the byte array to the crypto stream and flush it.cs.Write(data, 0, length);cs.FlushFinalBlock();// Get an array of bytes from the // MemoryStream that holds the // encrypted data.byte[] ret = ms.ToArray();// Close the streams.cs.Close();ms.Close();// Return the encrypted buffer.return ret;}catch (CryptographicException ex){Console.WriteLine("A cryptographic error occured: {0}", ex.Message);}return null;}public string EncryptString(string text){return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));}public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }public byte[] Decrypt(byte[] data, int length){try{// Create a new MemoryStream using the passed // array of encrypted data.MemoryStream ms = new MemoryStream(data);// Create a CryptoStream using the MemoryStream // and the passed key and initialization vector (IV).CryptoStream cs = new CryptoStream(ms,symm.CreateDecryptor(symm.Key, symm.IV),CryptoStreamMode.Read);// Create buffer to hold the decrypted data.byte[] result = new byte[length];// Read the decrypted data out of the crypto stream// and place it into the temporary buffer.cs.Read(result, 0, result.Length);return result;}catch (CryptographicException ex){Console.WriteLine("A cryptographic error occured: {0}", ex.Message);}return null;}public string DecryptString(string data){return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd('\0');}#endregion}

and use it like this: 并像这样使用它:

string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);// later
string actual=keys.DecryptString(encr);

#6楼

UPDATE 23/Dec/2015: Since this answer seems to be getting a lot of upvotes, I've updated it to fix silly bugs and to generally improve the code based upon comments and feedback. 更新2015年12月23日:由于这个答案似乎得到了很多赞成,我已经更新它以修复愚蠢的错误,并根据评论和反馈大致改进代码。 See the end of the post for a list of specific improvements. 有关具体改进的列表,请参阅帖子末尾。

As other people have said, Cryptography is not simple so it's best to avoid "rolling your own" encryption algorithm. 正如其他人所说,密码学并不简单,所以最好避免“滚动自己的”加密算法。

You can, however, "roll your own" wrapper class around something like the built-in RijndaelManaged cryptography class. 但是,你可以在内置的RijndaelManaged加密类之类的“滚动你自己的”包装类。

Rijndael is the algorithmic name of the current Advanced Encryption Standard , so you're certainly using an algorithm that could be considered "best practice". Rijndael是当前高级加密标准的算法名称,因此您肯定使用的算法可被视为“最佳实践”。

The RijndaelManaged class does indeed normally require you to "muck about" with byte arrays, salts, keys, initialization vectors etc. but this is precisely the kind of detail that can be somewhat abstracted away within your "wrapper" class. RijndaelManaged类确实通常要求您使用字节数组,salt,键,初始化向量等来“捣乱”,但这正是在“包装器”类中可以稍微抽象出来的那种细节。

The following class is one I wrote a while ago to perform exactly the kind of thing you're after, a simple single method call to allow some string-based plaintext to be encrypted with a string-based password, with the resulting encrypted string also being represented as a string. 下面的类是我前一段时间写的一个,用于执行你所追求的事情,一个简单的单一方法调用,允许一些基于字符串的明文用基于字符串的密码加密,生成的加密字符串也是被表示为一个字符串。 Of course, there's an equivalent method to decrypt the encrypted string with the same password. 当然,有一种等效方法可以用相同的密码解密加密的字符串。

Unlike the first version of this code, which used the exact same salt and IV values every time, this newer version will generate random salt and IV values each time. 与此代码的第一个版本不同,每次使用完全相同的salt和IV值时,这个较新的版本每次都会生成随机的salt和IV值。 Since salt and IV must be the same between the encryption and decryption of a given string, the salt and IV is prepended to the cipher text upon encryption and extracted from it again in order to perform the decryption. 由于在给定字符串的加密和解密之间盐和IV必须相同,因此在加密时将盐和IV预先加密到密文,并再次从密码中提取以便执行解密。 The result of this is that encrypting the exact same plaintext with the exact same password gives and entirely different ciphertext result each time. 结果是,用完全相同的密码加密完全相同的明文,每次都会产生完全不同的密文结果。

The "strength" of using this comes from using the RijndaelManaged class to perform the encryption for you, along with using the Rfc2898DeriveBytes function of the System.Security.Cryptography namespace which will generate your encryption key using a standard and secure algorithm (specifically, PBKDF2 ) based upon the string-based password you supply. 使用它的“优势”来自于使用RijndaelManaged类为您执行加密,以及使用System.Security.Cryptography命名空间的Rfc2898DeriveBytes函数,该函数将使用标准和安全算法生成加密密钥(特别是PBKDF2) )基于您提供的基于字符串的密码。 (Note this is an improvement of the first version's use of the older PBKDF1 algorithm). (注意,这是对第一个版本使用旧版PBKDF1算法的改进)。

Finally, it's important to note that this is still unauthenticated encryption. 最后,重要的是要注意这仍然是未经身份验证的加密。 Encryption alone provides only privacy (ie message is unknown to 3rd parties), whilst authenticated encryption aims to provide both privacy and authenticity (ie recipient knows message was sent by the sender). 仅加密仅提供隐私(即第三方不知道消息),而经认证的加密旨在提供隐私和真实性(即,收件人知道消息是由发送者发送的)。

Without knowing your exact requirements, it's difficult to say whether the code here is sufficiently secure for your needs, however, it has been produced to deliver a good balance between relative simplicity of implementation vs "quality". 在不知道您的确切要求的情况下,很难说这里的代码是否足以满足您的需求,但是,它的生成是为了在实现的相对简单性与“质量”之间实现良好的平衡。 For example, if your "receiver" of an encrypted string is receiving the string directly from a trusted "sender", then authentication may not even be necessary . 例如,如果加密字符串的“接收者”直接从受信任的“发件人”接收字符串,则甚至可能不需要身份验证。

If you require something more complex, and which offers authenticated encryption, check out this post for an implementation. 如果您需要更复杂的东西,并提供经过身份验证的加密,请查看此帖子以了解实施情况。

Here's the code: 这是代码:

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;namespace EncryptStringSample
{public static class StringCipher{// This constant is used to determine the keysize of the encryption algorithm in bits.// We divide this by 8 within the code below to get the equivalent number of bytes.private const int Keysize = 256;// This constant determines the number of iterations for the password bytes generation function.private const int DerivationIterations = 1000;public static string Encrypt(string plainText, string passPhrase){// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text// so that the same Salt and IV values can be used when decrypting.  var saltStringBytes = Generate256BitsOfRandomEntropy();var ivStringBytes = Generate256BitsOfRandomEntropy();var plainTextBytes = Encoding.UTF8.GetBytes(plainText);using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)){var keyBytes = password.GetBytes(Keysize / 8);using (var symmetricKey = new RijndaelManaged()){symmetricKey.BlockSize = 256;symmetricKey.Mode = CipherMode.CBC;symmetricKey.Padding = PaddingMode.PKCS7;using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)){using (var memoryStream = new MemoryStream()){using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)){cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);cryptoStream.FlushFinalBlock();// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.var cipherTextBytes = saltStringBytes;cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();memoryStream.Close();cryptoStream.Close();return Convert.ToBase64String(cipherTextBytes);}}}}}}public static string Decrypt(string cipherText, string passPhrase){// Get the complete stream of bytes that represent:// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)){var keyBytes = password.GetBytes(Keysize / 8);using (var symmetricKey = new RijndaelManaged()){symmetricKey.BlockSize = 256;symmetricKey.Mode = CipherMode.CBC;symmetricKey.Padding = PaddingMode.PKCS7;using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)){using (var memoryStream = new MemoryStream(cipherTextBytes)){using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)){var plainTextBytes = new byte[cipherTextBytes.Length];var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);memoryStream.Close();cryptoStream.Close();return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);}}}}}}private static byte[] Generate256BitsOfRandomEntropy(){var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.using (var rngCsp = new RNGCryptoServiceProvider()){// Fill the array with cryptographically secure random bytes.rngCsp.GetBytes(randomBytes);}return randomBytes;}}
}

The above class can be used quite simply with code similar to the following: 上面的类可以非常简单地使用类似于以下的代码:

using System;namespace EncryptStringSample
{class Program{static void Main(string[] args){Console.WriteLine("Please enter a password to use:");string password = Console.ReadLine();Console.WriteLine("Please enter a string to encrypt:");string plaintext = Console.ReadLine();Console.WriteLine("");Console.WriteLine("Your encrypted string is:");string encryptedstring = StringCipher.Encrypt(plaintext, password);Console.WriteLine(encryptedstring);Console.WriteLine("");Console.WriteLine("Your decrypted string is:");string decryptedstring = StringCipher.Decrypt(encryptedstring, password);Console.WriteLine(decryptedstring);Console.WriteLine("");Console.WriteLine("Press any key to exit...");Console.ReadLine();}}
}

(You can download a simple VS2013 sample solution (which includes a few unit tests) here ). (你可以下载一个简单的VS2013样品溶液(其中包括一些单元测试) 在这里 )。

UPDATE 23/Dec/2015: The list of specific improvements to the code are: 更新2015年12月23日:代码的具体改进列表如下:

  • Fixed a silly bug where encoding was different between encrypting and decrypting. 修复了加密和解密之间编码不同的愚蠢错误。 As the mechanism by which salt & IV values are generated has changed, encoding is no longer necessary. 由于生成盐和IV值的机制已经改变,因此不再需要编码。
  • Due to the salt/IV change, the previous code comment that incorrectly indicated that UTF8 encoding a 16 character string produces 32 bytes is no longer applicable (as encoding is no longer necessary). 由于salt / IV更改,以前的代码注释错误地指示UTF8编码16个字符的字符串产生32个字节不再适用(因为不再需要编码)。
  • Usage of the superseded PBKDF1 algorithm has been replaced with usage of the more modern PBKDF2 algorithm. 已取代的PBKDF1算法的使用已被更现代的PBKDF2算法的使用所取代。
  • The password derivation is now properly salted whereas previously it wasn't salted at all (another silly bug squished). 密码推导现在已经被正确腌制了,而之前它根本没有被腌制(另一个愚蠢的小虫被压扁)。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/667.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息