C# - .NET --- OpenSSL加密 AES


OpenSSL  AES加密原文:c# - 使用 .NET 类的 OpenSSL 加密 - 堆栈溢出 (stackoverflow.com)

  1 public class Protection
  2     {
  3         public string OpenSSLEncrypt(string plainText, string passphrase)
  4         {
  5             // generate salt
  6             byte[] key, iv;
  7             byte[] salt = new byte[8];
  8             RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  9             rng.GetNonZeroBytes(salt);
 10             DeriveKeyAndIV(passphrase, salt, out key, out iv);
 11             // encrypt bytes
 12             byte[] encryptedBytes = EncryptStringToBytesAes(plainText, key, iv);
 13             // add salt as first 8 bytes
 14             byte[] encryptedBytesWithSalt = new byte[salt.Length + encryptedBytes.Length + 8];
 15             Buffer.BlockCopy(Encoding.ASCII.GetBytes("Salted__"), 0, encryptedBytesWithSalt, 0, 8);
 16             Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 8, salt.Length);
 17             Buffer.BlockCopy(encryptedBytes, 0, encryptedBytesWithSalt, salt.Length + 8, encryptedBytes.Length);
 18             // base64 encode
 19             return Convert.ToBase64String(encryptedBytesWithSalt);
 20         }
 21 
 22         public string OpenSSLDecrypt(string encrypted, string passphrase)
 23         {
 24             // base 64 decode
 25             byte[] encryptedBytesWithSalt = Convert.FromBase64String(encrypted);
 26             // extract salt (first 8 bytes of encrypted)
 27             byte[] salt = new byte[8];
 28             byte[] encryptedBytes = new byte[encryptedBytesWithSalt.Length - salt.Length - 8];
 29             Buffer.BlockCopy(encryptedBytesWithSalt, 8, salt, 0, salt.Length);
 30             Buffer.BlockCopy(encryptedBytesWithSalt, salt.Length + 8, encryptedBytes, 0, encryptedBytes.Length);
 31             // get key and iv
 32             byte[] key, iv;
 33             DeriveKeyAndIV(passphrase, salt, out key, out iv);
 34             return DecryptStringFromBytesAes(encryptedBytes, key, iv);
 35         }
 36 
 37         private static void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv)
 38         {
 39             // generate key and iv
 40             List<byte> concatenatedHashes = new List<byte>(48);
 41 
 42             byte[] password = Encoding.UTF8.GetBytes(passphrase);
 43             byte[] currentHash = new byte[0];
 44             MD5 md5 = MD5.Create();
 45             bool enoughBytesForKey = false;
 46             // See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM
 47             while (!enoughBytesForKey)
 48             {
 49                 int preHashLength = currentHash.Length + password.Length + salt.Length;
 50                 byte[] preHash = new byte[preHashLength];
 51 
 52                 Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
 53                 Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length);
 54                 Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length);
 55 
 56                 currentHash = md5.ComputeHash(preHash);
 57                 concatenatedHashes.AddRange(currentHash);
 58 
 59                 if (concatenatedHashes.Count >= 48)
 60                     enoughBytesForKey = true;
 61             }
 62 
 63             key = new byte[32];
 64             iv = new byte[16];
 65             concatenatedHashes.CopyTo(0, key, 0, 32);
 66             concatenatedHashes.CopyTo(32, iv, 0, 16);
 67 
 68             md5.Clear();
 69             md5 = null;
 70         }
 71 
 72         static byte[] EncryptStringToBytesAes(string plainText, byte[] key, byte[] iv)
 73         {
 74             // Check arguments.
 75             if (plainText == null || plainText.Length <= 0)
 76                 throw new ArgumentNullException("plainText");
 77             if (key == null || key.Length <= 0)
 78                 throw new ArgumentNullException("key");
 79             if (iv == null || iv.Length <= 0)
 80                 throw new ArgumentNullException("iv");
 81 
 82             // Declare the stream used to encrypt to an in memory
 83             // array of bytes.
 84             MemoryStream msEncrypt;
 85 
 86             // Declare the RijndaelManaged object
 87             // used to encrypt the data.
 88             RijndaelManaged aesAlg = null;
 89 
 90             try
 91             {
 92                 // Create a RijndaelManaged object
 93                 // with the specified key and IV.
 94                 aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
 95 
 96                 // Create an encryptor to perform the stream transform.
 97                 ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
 98 
 99                 // Create the streams used for encryption.
100                 msEncrypt = new MemoryStream();
101                 using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
102                 {
103                     using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
104                     {
105 
106                         //Write all data to the stream.
107                         swEncrypt.Write(plainText);
108                         swEncrypt.Flush();
109                         swEncrypt.Close();
110                     }
111                 }
112             }
113             finally
114             {
115                 // Clear the RijndaelManaged object.
116                 if (aesAlg != null)
117                     aesAlg.Clear();
118             }
119 
120             // Return the encrypted bytes from the memory stream.
121             return msEncrypt.ToArray();
122         }
123 
124         static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
125         {
126             // Check arguments.
127             if (cipherText == null || cipherText.Length <= 0)
128                 throw new ArgumentNullException("cipherText");
129             if (key == null || key.Length <= 0)
130                 throw new ArgumentNullException("key");
131             if (iv == null || iv.Length <= 0)
132                 throw new ArgumentNullException("iv");
133 
134             // Declare the RijndaelManaged object
135             // used to decrypt the data.
136             RijndaelManaged aesAlg = null;
137 
138             // Declare the string used to hold
139             // the decrypted text.
140             string plaintext;
141 
142             try
143             {
144                 // Create a RijndaelManaged object
145                 // with the specified key and IV.
146                 aesAlg = new RijndaelManaged {Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv};
147 
148                 // Create a decrytor to perform the stream transform.
149                 ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
150                 // Create the streams used for decryption.
151                 using (MemoryStream msDecrypt = new MemoryStream(cipherText))
152                 {
153                     using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
154                     {
155                         using (StreamReader srDecrypt = new StreamReader(csDecrypt))
156                         {
157                             // Read the decrypted bytes from the decrypting stream
158                             // and place them in a string.
159                             plaintext = srDecrypt.ReadToEnd();
160                             srDecrypt.Close();
161                         }
162                     }
163                 }
164             }
165             finally
166             {
167                 // Clear the RijndaelManaged object.
168                 if (aesAlg != null)
169                     aesAlg.Clear();
170             }
171 
172             return plaintext;
173         }
174     }