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 }