diff --git a/Apewer/BytesUtility.cs b/Apewer/BytesUtility.cs index 4b76127..e81fd1a 100644 --- a/Apewer/BytesUtility.cs +++ b/Apewer/BytesUtility.cs @@ -767,6 +767,17 @@ namespace Apewer #endregion + #region PKCS #5 + + /// 使用密码生成密钥。 + static byte[] PKCS5(byte[] password, byte[] salt = null, int iterations = 1000, int bits = 32) + { + var rfc2898 = new Rfc2898DeriveBytes(password, salt, 1); + return rfc2898.GetBytes(32); + } + + #endregion + #region AES private static void Aes256(byte[] key, byte[] salt, Func create, Stream input, Stream output) @@ -842,6 +853,130 @@ namespace Apewer return result; } + private static readonly byte[] AesDefaultIV = new byte[16]; + + static T UseAes(byte[] key, byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, Func callback) + { + if (key == null) throw new ArgumentNullException(nameof(key)); + var keySize = key.Length * 8; + switch (keySize) + { + case 128: + case 192: + case 256: + break; + default: + throw new ArgumentException($"密钥大小【{keySize}】bits 无效。"); + } + + if (iv == null) iv = AesDefaultIV; + var ivSize = iv.Length * 8; + if (ivSize != 128) throw new ArgumentException($"初始化向量【{ivSize}】bits 无效。"); + + using (var rijndael = new RijndaelManaged()) + { + rijndael.Key = key; + rijndael.IV = iv; + rijndael.Mode = cipherMode; + rijndael.Padding = paddingMode; + + return callback.Invoke(rijndael); + } + } + + static void UseAes(Stream input, Stream output, byte[] key, byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, Func create) + { + if (input == null) throw new ArgumentNullException(nameof(input)); + if (output == null) throw new ArgumentNullException(nameof(output)); + + UseAes(key, iv, cipherMode, paddingMode, rijndael => + { + using (var transformer = create.Invoke(rijndael)) + { + + using (var stream = new CryptoStream(output, transformer, CryptoStreamMode.Write)) + { + Read(input, stream); + stream.Close(); + } + } + return null; + }); + } + + static byte[] UseAes(byte[] input, byte[] key, byte[] iv, CipherMode cipherMode, PaddingMode paddingMode, Func create) + { + if (input == null) input = new byte[0]; + + var result = null as byte[]; + return UseAes(key, iv, cipherMode, paddingMode, rijndael => + { + using (var transformer = create.Invoke(rijndael)) + { + var result = transformer.TransformFinalBlock(input, 0, input.Length); + return result; + } + }); + } + + /// 执行 AES 128/192/256 加密。 + /// 明文。 + /// 密钥。 + /// 块密码模式。 + /// 填充模式。 + /// + /// + /// + /// + public static byte[] AesEncrypt(byte[] plain, byte[] key, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) + { + return UseAes(plain, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + } + + /// 执行 AES 128/192/256 加密。 + /// 明文。 + /// 密钥,长度必须是 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。 + /// 初始化向量,必须是 128 位(16 字节)。 + /// 块密码模式。 + /// 填充模式。 + /// + /// + /// + /// + public static byte[] AesEncrypt(byte[] plain, byte[] key, byte[] iv, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) + { + return UseAes(plain, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + } + + /// 执行 AES 128/192/256 解密。 + /// 密文。 + /// 密钥,长度必须是 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。 + /// 块密码模式。 + /// 填充模式。 + /// + /// + /// + /// + public static byte[] AesDecrypt(byte[] cipher, byte[] key, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) + { + return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + } + + /// 执行 AES 128/192/256 解密。 + /// 密文。 + /// 密钥,长度必须是 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。 + /// 初始化向量,必须是 128 位(16 字节)。 + /// 块密码模式。 + /// 填充模式。 + /// + /// + /// + /// + public static byte[] AesDecrypt(byte[] cipher, byte[] key, byte[] iv, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) + { + return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + } + #endregion #region Hash