fork(6) download
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Security.Cryptography;
  5.  
  6. /// <summary>
  7. /// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and
  8. /// decrypt data. As long as encryption and decryption routines use the same
  9. /// parameters to generate the keys, the keys are guaranteed to be the same.
  10. /// The class uses static functions with duplicate code to make it easier to
  11. /// demonstrate encryption and decryption logic. In a real-life application,
  12. /// this may not be the most efficient way of handling encryption, so - as
  13. /// soon as you feel comfortable with it - you may want to redesign this class.
  14. /// </summary>
  15. public class RijndaelSimple
  16. {
  17. /// <summary>
  18. /// Encrypts specified plaintext using Rijndael symmetric key algorithm
  19. /// and returns a base64-encoded result.
  20. /// </summary>
  21. /// <param name="plainText">
  22. /// Plaintext value to be encrypted.
  23. /// </param>
  24. /// <param name="passPhrase">
  25. /// Passphrase from which a pseudo-random password will be derived. The
  26. /// derived password will be used to generate the encryption key.
  27. /// Passphrase can be any string. In this example we assume that this
  28. /// passphrase is an ASCII string.
  29. /// </param>
  30. /// <param name="saltValue">
  31. /// Salt value used along with passphrase to generate password. Salt can
  32. /// be any string. In this example we assume that salt is an ASCII string.
  33. /// </param>
  34. /// <param name="hashAlgorithm">
  35. /// Hash algorithm used to generate password. Allowed values are: "MD5" and
  36. /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
  37. /// </param>
  38. /// <param name="passwordIterations">
  39. /// Number of iterations used to generate password. One or two iterations
  40. /// should be enough.
  41. /// </param>
  42. /// <param name="initVector">
  43. /// Initialization vector (or IV). This value is required to encrypt the
  44. /// first block of plaintext data. For RijndaelManaged class IV must be
  45. /// exactly 16 ASCII characters long.
  46. /// </param>
  47. /// <param name="keySize">
  48. /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
  49. /// Longer keys are more secure than shorter keys.
  50. /// </param>
  51. /// <returns>
  52. /// Encrypted value formatted as a base64-encoded string.
  53. /// </returns>
  54. public static string Encrypt
  55. (
  56. string plainText,
  57. string passPhrase,
  58. string saltValue,
  59. string hashAlgorithm,
  60. int passwordIterations,
  61. string initVector,
  62. int keySize
  63. )
  64. {
  65. // Convert strings into byte arrays.
  66. // Let us assume that strings only contain ASCII codes.
  67. // If strings include Unicode characters, use Unicode, UTF7, or UTF8
  68. // encoding.
  69. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
  70. byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
  71.  
  72. // Convert our plaintext into a byte array.
  73. // Let us assume that plaintext contains UTF8-encoded characters.
  74. byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
  75.  
  76. // First, we must create a password, from which the key will be derived.
  77. // This password will be generated from the specified passphrase and
  78. // salt value. The password will be created using the specified hash
  79. // algorithm. Password creation can be done in several iterations.
  80. PasswordDeriveBytes password = new PasswordDeriveBytes
  81. (
  82. passPhrase,
  83. saltValueBytes,
  84. hashAlgorithm,
  85. passwordIterations
  86. );
  87.  
  88. // Use the password to generate pseudo-random bytes for the encryption
  89. // key. Specify the size of the key in bytes (instead of bits).
  90. byte[] keyBytes = password.GetBytes(keySize / 8);
  91.  
  92. // Create uninitialized Rijndael encryption object.
  93. RijndaelManaged symmetricKey = new RijndaelManaged();
  94.  
  95. // It is reasonable to set encryption mode to Cipher Block Chaining
  96. // (CBC). Use default options for other symmetric key parameters.
  97. symmetricKey.Mode = CipherMode.CBC;
  98.  
  99. // Generate encryptor from the existing key bytes and initialization
  100. // vector. Key size will be defined based on the number of the key
  101. // bytes.
  102. ICryptoTransform encryptor = symmetricKey.CreateEncryptor
  103. (
  104. keyBytes,
  105. initVectorBytes
  106. );
  107.  
  108. // Define memory stream which will be used to hold encrypted data.
  109. MemoryStream memoryStream = new MemoryStream();
  110.  
  111. // Define cryptographic stream (always use Write mode for encryption).
  112. CryptoStream cryptoStream = new CryptoStream
  113. (
  114. memoryStream,
  115. encryptor,
  116. CryptoStreamMode.Write
  117. );
  118.  
  119. // Start encrypting.
  120. cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
  121.  
  122. // Finish encrypting.
  123. cryptoStream.FlushFinalBlock();
  124.  
  125. // Convert our encrypted data from a memory stream into a byte array.
  126. byte[] cipherTextBytes = memoryStream.ToArray();
  127.  
  128. // Close both streams.
  129. memoryStream.Close();
  130. cryptoStream.Close();
  131.  
  132. // Convert encrypted data into a base64-encoded string.
  133. string cipherText = Convert.ToBase64String(cipherTextBytes);
  134.  
  135. // Return encrypted string.
  136. return cipherText;
  137. }
  138.  
  139. /// <summary>
  140. /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
  141. /// </summary>
  142. /// <param name="cipherText">
  143. /// Base64-formatted ciphertext value.
  144. /// </param>
  145. /// <param name="passPhrase">
  146. /// Passphrase from which a pseudo-random password will be derived. The
  147. /// derived password will be used to generate the encryption key.
  148. /// Passphrase can be any string. In this example we assume that this
  149. /// passphrase is an ASCII string.
  150. /// </param>
  151. /// <param name="saltValue">
  152. /// Salt value used along with passphrase to generate password. Salt can
  153. /// be any string. In this example we assume that salt is an ASCII string.
  154. /// </param>
  155. /// <param name="hashAlgorithm">
  156. /// Hash algorithm used to generate password. Allowed values are: "MD5" and
  157. /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
  158. /// </param>
  159. /// <param name="passwordIterations">
  160. /// Number of iterations used to generate password. One or two iterations
  161. /// should be enough.
  162. /// </param>
  163. /// <param name="initVector">
  164. /// Initialization vector (or IV). This value is required to encrypt the
  165. /// first block of plaintext data. For RijndaelManaged class IV must be
  166. /// exactly 16 ASCII characters long.
  167. /// </param>
  168. /// <param name="keySize">
  169. /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
  170. /// Longer keys are more secure than shorter keys.
  171. /// </param>
  172. /// <returns>
  173. /// Decrypted string value.
  174. /// </returns>
  175. /// <remarks>
  176. /// Most of the logic in this function is similar to the Encrypt
  177. /// logic. In order for decryption to work, all parameters of this function
  178. /// - except cipherText value - must match the corresponding parameters of
  179. /// the Encrypt function which was called to generate the
  180. /// ciphertext.
  181. /// </remarks>
  182. public static string Decrypt
  183. (
  184. string cipherText,
  185. string passPhrase,
  186. string saltValue,
  187. string hashAlgorithm,
  188. int passwordIterations,
  189. string initVector,
  190. int keySize
  191. )
  192. {
  193. // Convert strings defining encryption key characteristics into byte
  194. // arrays. Let us assume that strings only contain ASCII codes.
  195. // If strings include Unicode characters, use Unicode, UTF7, or UTF8
  196. // encoding.
  197. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
  198. byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
  199.  
  200. // Convert our ciphertext into a byte array.
  201. byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
  202.  
  203. // First, we must create a password, from which the key will be
  204. // derived. This password will be generated from the specified
  205. // passphrase and salt value. The password will be created using
  206. // the specified hash algorithm. Password creation can be done in
  207. // several iterations.
  208. PasswordDeriveBytes password = new PasswordDeriveBytes
  209. (
  210. passPhrase,
  211. saltValueBytes,
  212. hashAlgorithm,
  213. passwordIterations
  214. );
  215.  
  216. // Use the password to generate pseudo-random bytes for the encryption
  217. // key. Specify the size of the key in bytes (instead of bits).
  218. byte[] keyBytes = password.GetBytes(keySize / 8);
  219.  
  220. // Create uninitialized Rijndael encryption object.
  221. RijndaelManaged symmetricKey = new RijndaelManaged();
  222.  
  223. // It is reasonable to set encryption mode to Cipher Block Chaining
  224. // (CBC). Use default options for other symmetric key parameters.
  225. symmetricKey.Mode = CipherMode.CBC;
  226.  
  227. // Generate decryptor from the existing key bytes and initialization
  228. // vector. Key size will be defined based on the number of the key
  229. // bytes.
  230. ICryptoTransform decryptor = symmetricKey.CreateDecryptor
  231. (
  232. keyBytes,
  233. initVectorBytes
  234. );
  235.  
  236. // Define memory stream which will be used to hold encrypted data.
  237. MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
  238.  
  239. // Define cryptographic stream (always use Read mode for encryption).
  240. CryptoStream cryptoStream = new CryptoStream
  241. (
  242. memoryStream,
  243. decryptor,
  244. CryptoStreamMode.Read
  245. );
  246.  
  247. // Since at this point we don't know what the size of decrypted data
  248. // will be, allocate the buffer long enough to hold ciphertext;
  249. // plaintext is never longer than ciphertext.
  250. byte[] plainTextBytes = new byte[cipherTextBytes.Length];
  251.  
  252. // Start decrypting.
  253. int decryptedByteCount = cryptoStream.Read
  254. (
  255. plainTextBytes,
  256. 0,
  257. plainTextBytes.Length
  258. );
  259.  
  260. // Close both streams.
  261. memoryStream.Close();
  262. cryptoStream.Close();
  263.  
  264. // Convert decrypted data into a string.
  265. // Let us assume that the original plaintext string was UTF8-encoded.
  266. string plainText = Encoding.UTF8.GetString
  267. (
  268. plainTextBytes,
  269. 0,
  270. decryptedByteCount
  271. );
  272.  
  273. // Return decrypted string.
  274. return plainText;
  275. }
  276. }
  277.  
  278. /// <summary>
  279. /// Illustrates the use of RijndaelSimple class to encrypt and decrypt data.
  280. /// </summary>
  281. public class RijndaelSimpleTest
  282. {
  283. /// <summary>
  284. /// The main entry point for the application.
  285. /// </summary>
  286. [STAThread]
  287. static void Main(string[] args)
  288. {
  289. string plainText = "1231231231"; // original plaintext
  290.  
  291. string passPhrase = "Status#1"; // can be any string
  292. string saltValue = "Ep1kS@lt"; // can be any string
  293. string hashAlgorithm = "SHA1"; // can be "MD5"
  294. int passwordIterations= 2; // can be any number
  295. string initVector = "@1G2c7A4r5T6H7J4"; // must be 16 bytes
  296. int keySize = 256; // can be 192 or 128
  297.  
  298. Console.WriteLine(String.Format("Plaintext : {0}", plainText));
  299.  
  300. string cipherText = RijndaelSimple.Encrypt
  301. (
  302. plainText,
  303. passPhrase,
  304. saltValue,
  305. hashAlgorithm,
  306. passwordIterations,
  307. initVector,
  308. keySize
  309. );
  310.  
  311. Console.WriteLine(String.Format("Encrypted : {0}", cipherText));
  312.  
  313. plainText = RijndaelSimple.Decrypt
  314. (
  315. cipherText,
  316. passPhrase,
  317. saltValue,
  318. hashAlgorithm,
  319. passwordIterations,
  320. initVector,
  321. keySize
  322. );
  323.  
  324. Console.WriteLine(String.Format("Decrypted : {0}", plainText));
  325. }
  326. }
Success #stdin #stdout 0.09s 34360KB
stdin
Standard input is empty
stdout
Plaintext : 1231231231
Encrypted : tOiDEWsJGTpKCDaOkXhZ6w==
Decrypted : 1231231231