using Apewer.Internals; using Externals.Compression.Checksums; using Externals.Compression.Zip; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Security.Cryptography; using System.Text; namespace Apewer { /// 二进制。 public static class BytesUtility { /// 空字节数组,每次获取都将创建新的引用。 public static byte[] Empty = new byte[0]; /// 默认缓冲区大小。 public const int DefaultBuffer = 4096; // 预置十六进制字符。 private static readonly char[] UpperHex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private static readonly char[] LowerHex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; #region ASCII /// CRLF public static byte[] CRLF { get => new byte[] { 13, 10 }; } /// CR public static byte[] CR { get => new byte[] { 13 }; } /// LF public static byte[] LF { get => new byte[] { 10 }; } #endregion #region Bytes Array /// 克隆字节数组。当源为 NULL 时获取零元素字节数组。 public static byte[] Clone(this byte[] bytes) { if (bytes == null) return Empty; var length = bytes.Length; if (length < 1) return Empty; var result = new byte[length]; Buffer.BlockCopy(bytes, 0, result, 0, length); return result; } /// 每个字节取反。 /// value = 255 - value public static byte[] Adverse(this byte[] bytes) { if (bytes == null || bytes.LongLength < 1L) return Empty; var adverse = new byte[bytes.LongLength]; for (var i = 0L; i < bytes.LongLength; i++) adverse[i] = Convert.ToByte(255 - bytes[i]); return adverse; } /// 确定此字节数组实例的开头是否与指定的字节数组匹配。 public static bool StartsWith(this byte[] bytes, params byte[] head) { // 头部为空,视为匹配。 if (head == null) return true; var length = head.Length; if (length < 1) return true; // 样本为空,视为不匹配。 if (bytes == null) return false; if (bytes.Length < length) return false; // 对比头部字节。 for (var i = 0; i < length; i++) { if (bytes[i] != head[i]) return false; } return true; } /// 确定此字节数组实例的结尾是否与指定的字节数组匹配。 public static bool EndsWith(this byte[] bytes, params byte[] foot) { // 尾部为空,视为匹配。 if (foot == null) return true; var length = foot.Length; if (length < 1) return true; // 样本为空,视为不匹配。 if (bytes == null) return false; if (bytes.Length < length) return false; // 对比尾部字节。 var offset = bytes.Length - length; for (var i = 0; i < length; i++) { if (bytes[offset + i] != foot[i]) return false; } return true; } /// 合并字节数组。 public static byte[] Merge(IEnumerable array) { if (array == null) return Empty; var total = 0L; foreach (var bytes in array) { if (bytes == null) continue; total += bytes.LongLength; } var result = new byte[total]; var offset = 0L; if (total > 0) { foreach (var bytes in array) { if (bytes == null) continue; var length = bytes.LongLength; if (length < 1L) continue; Array.Copy(bytes, 0L, result, offset, length); offset += length; } } return result; } /// 合并字节数组。 public static byte[] Merge(params byte[][] array) => Merge(array as IEnumerable); /// 为字节数组增加字节。 public static byte[] Append(byte[] head, params byte[] bytes) => Merge(head, bytes); /// 为文本数据添加 BOM 字节,若已存在则忽略。 public static byte[] AddTextBom(this byte[] bytes) { var bom = new byte[] { 0xEF, 0xBB, 0xBF }; if (bytes == null || bytes.LongLength < 1L) return bom; var hasBom = (bytes.Length >= 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF); return hasBom ? Merge(bytes) : Merge(bom, bytes); } /// 去除文本数据的 BOM 字节,若不存在则忽略。 public static byte[] WipeTextBom(this byte[] bytes) { if (bytes == null) return Empty; var hasBom = (bytes.Length >= 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF); var offset = hasBom ? 3 : 0; var length = bytes.Length - offset; var wiped = new byte[length]; if (length > 0) Array.Copy(bytes, offset, wiped, 0, length); return wiped; } /// 生成新的 GUID 数据。 public static byte[] NewGuid() => Guid.NewGuid().ToByteArray(); #endregion #region Text /// 将字节数组转换为十六进制文本。 public static string ToHex(this byte[] bytes) { int length = bytes.Length; if (length > 0) { var sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.Append(Constant.HexCollection[bytes[i] / 16]); sb.Append(Constant.HexCollection[bytes[i] % 16]); } return sb.ToString(); } return ""; } /// 将十六进制文本转换为字节数组。 public static byte[] FromHex(this string hex) { if (string.IsNullOrEmpty(hex) || hex.Length < 2) return Empty; if (hex.Length % 2 != 0) return Empty; var lower = hex.ToLower().ToCharArray(); var half = lower.Length / 2; var bytes = new byte[half]; for (var i = 0; i < half; i++) { var offset = i * 2; var h = Constant.HexCollection.IndexOf(lower[offset]); var l = Constant.HexCollection.IndexOf(lower[offset + 1]); if (h < 0 || l < 0) return Empty; bytes[i] = Convert.ToByte((h * 16) + l); } return bytes; } /// 将字节数组格式化为十六进制字符串,可指定大小写。 /// 例:D41D8CD98F00B204E9800998ECF8427E public static string ToX2(this byte[] bytes, bool upper = true) { if (bytes == null) return ""; var length = bytes.Length; if (length < 1) return TextUtility.Empty; var hex = upper ? UpperHex : LowerHex; var chars = new char[length * 2]; for (var i = 0; i < length; i++) { var b = bytes[i]; var offset = i * 2; chars[offset] = hex[b / 16]; chars[offset + 1] = hex[b % 16]; } return new string(chars); } /// Byte[] -> Base64 public static string ToBase64(params byte[] bytes) { if (bytes == null || bytes.Length < 1) return Constant.EmptyString; try { return Convert.ToBase64String(bytes); } catch { return Constant.EmptyString; } } /// Base64 -> Byte[] public static byte[] FromBase64(string base64) { if (string.IsNullOrEmpty(base64)) return Empty; try { return Convert.FromBase64String(base64); } catch { return Empty; } } /// 转换字节数组为文本,默认使用 UTF-8 代码页。 public static string ToText(byte[] bytes, Encoding encoding = null) { if (bytes.Length < 1) return Constant.EmptyString; try { return (encoding ?? Encoding.UTF8).GetString(bytes); } catch { return Constant.EmptyString; } } /// 转换文本为字节数组,默认使用 UTF-8 代码页。 public static byte[] FromText(string text, Encoding encoding = null) { if (string.IsNullOrEmpty(text)) return Empty; try { return (encoding ?? Encoding.UTF8).GetBytes(text); } catch { return Empty; } } #endregion #region 压缩、解压。 /// 对数据进行 GZip 压缩。 public static byte[] ToGzip(byte[] plain) { if (plain == null || plain.Length == 0) return Empty; byte[] result; using (var output = new MemoryStream()) { using (var zip = new GZipStream(output, CompressionMode.Compress, true)) { zip.Write(plain, 0, plain.Length); } result = output.ToArray(); } return result; } /// 对数据进行 GZip 解压。 public static byte[] FromGzip(byte[] gzip) { if (gzip == null || gzip.Length == 0) return Empty; byte[] result; using (var input = new MemoryStream(gzip)) { input.Position = 0; using (var output = new MemoryStream()) { using (var zip = new GZipStream(input, CompressionMode.Decompress, true)) { Read(zip, output, null, 8192); result = output.ToArray(); } } } return result; } /// 压缩字典为 ZIP 文件。 /// 由文件名和文件内容组成的字典。 /// 要输出的 ZIP 流。 public static Exception ToZip(Dictionary files, Stream target) { var zip = null as ZipOutputStream; try { if (files == null) return new ArgumentNullException(); if (target == null) return new ArgumentNullException(); if (!target.CanWrite) return new NotSupportedException(); zip = new ZipOutputStream(target); zip.SetLevel(1); foreach (var file in files) { var crc = new Crc32(); crc.Reset(); crc.Update(file.Value); var zipentry = new ZipEntry(file.Key); zipentry.CompressionMethod = CompressionMethod.Deflated; //vzipentry.Size = vfile.Value.LongLength; zipentry.Crc = crc.Value; zipentry.IsUnicodeText = true; zip.PutNextEntry(zipentry); zip.Write(file.Value, 0, file.Value.Length); zip.CloseEntry(); } zip.IsStreamOwner = false; zip.Finish(); zip.Flush(); zip.Close(); return null; } catch (Exception ex) { RuntimeUtility.Dispose(zip); return ex; } } /// 压缩到 ZIP 流。 /// ZIP 内的文件名。 /// 要输出的 ZIP 流。 /// 按名称获取文件的输入流。 /// 按名称获取文件的修改时间。 /// 释放已写入 ZIP 的输入流。 public static Exception ToZip(IEnumerable names, Stream target, Func inputGetter, Func modifildGetter = null, bool disposeFiles = false) { var zip = null as ZipOutputStream; try { if (names == null) return new ArgumentNullException("names"); if (target == null) return new ArgumentNullException("target"); if (!target.CanWrite) return new ArgumentNullException("target"); zip = new ZipOutputStream(target); zip.SetLevel(1); foreach (var name in names) { if (string.IsNullOrEmpty(name)) continue; // stream var capacity = 1024; var input = inputGetter == null ? null : inputGetter(name); if (input != null) { if (!input.CanSeek || !input.CanRead) { if (disposeFiles) RuntimeUtility.Dispose(input); return new NotSupportedException("获取到的输入流不支持 Seek 或 Read。"); } } var crc = new Crc32(); crc.Reset(); if (input != null) { input.ResetPosition(); while (true) { var count = 0; var buffer = new byte[capacity]; count = input.Read(buffer, 0, buffer.Length); if (count == 0) break; crc.Update(buffer, 0, count); } } var entry = new ZipEntry(name); entry.CompressionMethod = CompressionMethod.Deflated; //vzipentry.Size = vfile.Value.LongLength; entry.Crc = crc.Value; entry.IsUnicodeText = true; if (modifildGetter != null) entry.DateTime = modifildGetter(name); zip.PutNextEntry(entry); if (input != null) { input.ResetPosition(); while (true) { var count = 0; var buffer = new byte[capacity]; count = input.Read(buffer, 0, buffer.Length); if (count == 0) break; zip.Write(buffer, 0, count); } } zip.CloseEntry(); if (disposeFiles) RuntimeUtility.Dispose(input); } zip.IsStreamOwner = false; zip.Finish(); zip.Flush(); zip.Close(); return null; } catch (Exception ex) { RuntimeUtility.Dispose(zip); return ex; } } /// 压缩字典为 ZIP 包。 /// 由文件名和文件内容组成的字典。 public static byte[] ToZip(Dictionary files) { if (files == null) return null; var output = new MemoryStream(); var input = null as Stream; var ex = ToZip(files.Keys, output, (name) => { RuntimeUtility.Dispose(input); if (name.IsEmpty()) return null; var bytes = files[name]; if (bytes == null || bytes.LongLength < 1L) return null; input = new MemoryStream(); Write(input, bytes); return input; }, null, true); RuntimeUtility.Dispose(input); var result = output.ToArray(); RuntimeUtility.Dispose(result); return result; } /// 解压 ZIP 文件。 public static Exception FromZip(Stream input, ZipOnFile onFile, ZipOnDirectory onDirectory = null, bool disposeOutput = false) { const int BufferCapacity = 1024; var zip = null as ZipInputStream; try { if (input == null) return new ArgumentNullException("input"); if (!input.CanRead) return new NotSupportedException(); if (onFile == null) return new ArgumentNullException("extraction"); zip = new ZipInputStream(input); while (true) { var entry = zip.GetNextEntry(); if (entry == null) break; var name = entry.Name; var size = entry.Size; var modified = entry.DateTime; if (entry.IsFile) { var output = null as Stream; try { output = onFile(name, size, modified); if (output == null) continue; if (!output.CanWrite) { RuntimeUtility.Dispose(output); continue; } var writed = 0L; while (true) { var buffer = new byte[BufferCapacity]; var count = zip.Read(buffer, 0, BufferCapacity); writed += count; if (count < 1) break; output.Write(buffer, 0, count); } if (disposeOutput) RuntimeUtility.Dispose(output, true); } catch (Exception ex) { if (disposeOutput) RuntimeUtility.Dispose(output, true); RuntimeUtility.Dispose(zip); return ex; } } if (onDirectory != null && entry.IsDirectory) { try { onDirectory(name, modified); } catch (Exception ex) { RuntimeUtility.Dispose(zip); return ex; } } } zip.Dispose(); return null; } catch (Exception ex) { RuntimeUtility.Dispose(zip); return ex; } } /// 解压 .ZIP 文件为字典。 public static Dictionary FromZip(byte[] zip) { var result = new Dictionary(); if (zip == null) return result; if (zip.LongLength < 1) return result; var packagememory = new System.IO.MemoryStream(zip); try { var zipstream = new ZipInputStream(packagememory); while (true) { var entry = zipstream.GetNextEntry(); if (entry == null) break; if (entry.IsFile) { var cellname = entry.Name; var celldata = new byte[0]; { var cellstream = new System.IO.MemoryStream(); while (true) { var blockdata = new byte[1024]; var blockread = zipstream.Read(blockdata, 0, 1024); if (blockread < 1) break; cellstream.Write(blockdata, 0, blockread); } celldata = cellstream.ToArray(); cellstream.Dispose(); } if (result.ContainsKey(cellname)) result[cellname] = celldata; else result.Add(cellname, celldata); } } zipstream.Dispose(); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } packagememory.Dispose(); return result; } #endregion #region Stream /// 关闭,并释放流。 public static void Dispose(Stream stream, bool flush = false, bool close = true) { if (stream != null) { try { if (flush) stream.Flush(); } catch { } try { if (close) stream.Close(); } catch { } try { stream.Dispose(); } catch { } } } /// 关闭,并释放流。 public static void Dispose(IEnumerable streams, bool flush = false, bool close = true) { if (streams != null) { foreach (var stream in streams) Dispose(stream, flush, close); } } /// 重置流的位置到开始位置。 public static bool ResetPosition(Stream stream) { if (stream == null) return false; try { stream.Position = 0; if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin); return true; } catch { return false; } } /// 读取源流中的数据,并将数据写入目标流,获取写入的总字节数。 /// 要读取的源流。 /// 要写入的目标流。 /// 已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。 /// 缓冲区大小,最小值为 1。 /// 已写入的字节数。 public static long Read(Stream source, Stream destination, Func progress = null, int buffer = DefaultBuffer) { if (source == null || !source.CanRead) return 0; if (destination == null || !destination.CanWrite) return 0; var limit = buffer < 1 ? 1 : buffer; var total = 0L; var count = 0; var callback = progress == null ? false : true; while (true) { count = 0; var temp = new byte[limit]; try { count = source.Read(temp, 0, limit); if (count < 1) break; } catch { break; } try { destination.Write(temp, 0, count); } catch { break; } total += count; if (callback) { var @continue = progress(total); if (!@continue) break; } } return total; } /// 读取源流中的数据,并将数据写入目标流,获取写入的总字节数。 /// 要读取的源流。 /// 要写入的目标流。 /// 已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。 /// 缓冲区大小,最小值为 1。 /// 已写入的字节数。 public static long Read(Stream source, Stream destination, Action progress, int buffer = DefaultBuffer) { return Read(source, destination, (x) => { progress?.Invoke(x); return true; }, buffer); } /// 读取源流中的数据。 /// 源流。 /// 缓冲区大小,最小值为 1。 /// 读取结束后释放源流。 public static byte[] Read(Stream source, int buffer = 4096, bool dispose = false) { var result = null as byte[]; using (var memory = new MemoryStream()) { Read(source, memory, null, buffer); result = memory.ToArray(); } if (dispose) Dispose(source); return result; } /// 读取源流中的数据。 /// 源流。 /// 读取结束后释放源流。 public static byte[] Read(Stream source, bool dispose) => Read(source, DefaultBuffer, dispose); /// 读取源流中的数据,并将数据写入目标流,获取写入的总字节数。 /// 要读取的源流。 /// 要写入的目标流。 /// 已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。 /// 缓冲区大小,最小值为 1。 /// 已写入的字节数。 public static long Read(IEnumerable sources, Stream destination, Func writed = null, int buffer = DefaultBuffer) { var total = 0L; if (sources != null) { if (writed == null) { foreach (var source in sources) total += Read(source, destination, null, buffer); } else { foreach (var source in sources) { Read(source, destination, (x) => { total += x; return writed(total); }, buffer); } } } return total; } /// 读取源流中的数据,并将数据写入目标流,获取写入的总字节数。 /// 要读取的源流。 /// 要写入的目标流。 /// 已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。 /// 缓冲区大小,最小值为 1。 /// 已写入的字节数。 public static long Read(IEnumerable sources, Stream destination, Action writed, int buffer = DefaultBuffer) { return Read(sources, destination, (x) => { writed?.Invoke(x); return true; }, buffer); } /// 向目标流写入数据,最多可写入 2147483648 字节。 public static int Write(Stream destination, byte[] bytes, Action writed, int buffer = DefaultBuffer) { if (destination == null || !destination.CanWrite) return 0; if (bytes == null || bytes.Length < 1 || bytes.LongLength > int.MaxValue) return 0; var limit = buffer < 1 ? 1 : buffer; var total = 0; try { var length = bytes.Length; while (total < length) { var block = length - total; if (block > limit) block = limit; destination.Write(bytes, total, block); total += block; writed?.Invoke(total); } } catch (Exception ex) { Logger.Internals.Exception($"{nameof(BytesUtility)}.{nameof(Write)}", ex); } return total; } /// 向目标流写入数据,最多可写入 2147483647 字节(> 20 GB)。 public static int Write(Stream destination, params byte[] bytes) => Write(destination, bytes, null); #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) { using (var rm = new RijndaelManaged()) { rm.KeySize = 256; rm.BlockSize = 128; rm.Mode = CipherMode.ECB; rm.Padding = PaddingMode.PKCS7; var k = new Rfc2898DeriveBytes(SHA256(key), salt, 1); rm.Key = k.GetBytes(32); rm.IV = k.GetBytes(16); using (var ct = create.Invoke(rm)) { using (var cs = new CryptoStream(output, ct, CryptoStreamMode.Write)) { Read(input, cs); cs.Close(); } } } } /// 执行 AES 加密。 public static void Aes256Encrypt(Stream input, Stream output, byte[] key) => Aes256(key, key, rm => rm.CreateEncryptor(), input, output); /// 执行 AES 解密。 public static void Aes256Decrypt(Stream input, Stream output, byte[] key) => Aes256(key, key, rm => rm.CreateDecryptor(), input, output); private static RijndaelManaged Aes256Provider(byte[] key) { var k = key ?? Empty; // AesFill(key); var p = new RijndaelManaged(); p.Key = k; p.Mode = CipherMode.ECB; p.Padding = PaddingMode.PKCS7; return p; } /// 对数据进行 AES 加密。 public static byte[] Aes256Encrypt(byte[] bytes, byte[] key = null) { if (bytes == null) return Empty; if (bytes.Length == 0) return Empty; var rm = Aes256Provider(key); var result = new byte[0]; var ct = rm.CreateEncryptor(); try { result = ct.TransformFinalBlock(bytes, 0, bytes.Length); } catch { } return result; } /// 对数据进行 AES 解密。 public static byte[] Aes256Decrypt(byte[] cipher, byte[] key = null) { if (cipher == null) return Empty; if (cipher.Length == 0) return Empty; var rm = Aes256Provider(key); var result = new byte[0]; var ct = rm.CreateDecryptor(); try { result = ct.TransformFinalBlock(cipher, 0, cipher.Length); } catch { } ct.Dispose(); 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 private static byte[] ComputeHash(byte[] bytes) where T : HashAlgorithm, new() { if (bytes != null) { try { using (var algorithm = new T()) { var result = algorithm.ComputeHash(bytes); algorithm.Clear(); return result; } } catch { } } return Empty; } private static byte[] ComputeHash(Stream stream, Action progress) where T : HashAlgorithm, new() { if (progress == null) { using (var algorithm = new T()) { if (stream == null) { var result = algorithm.ComputeHash(Empty); algorithm.Clear(); return result; } else { var result = algorithm.ComputeHash(stream); algorithm.Clear(); return result; } } } else { if (stream == null) return Empty; // 初始化。 using (var algorithm = new T()) { algorithm.Initialize(); // 读取。 var count = 0; var input = new byte[DefaultBuffer]; var output = new byte[DefaultBuffer]; while (true) { count = stream.Read(input, 0, DefaultBuffer); if (count < DefaultBuffer) { algorithm.TransformFinalBlock(input, 0, count); break; } else { algorithm.TransformBlock(input, 0, count, output, 0); } } var result = algorithm.Hash; algorithm.Clear(); return result; } } } /// 获取 MD5 值。 public static byte[] MD5(this byte[] bytes) => ComputeHash(bytes); /// 获取 MD5 值。 public static byte[] MD5(this Stream stream, Action progress = null) => ComputeHash(stream, progress); /// 获取 SHA1 值。 public static byte[] SHA1(this byte[] bytes) => ComputeHash(bytes); /// 获取 SHA1 值。 public static byte[] SHA1(this Stream stream, Action progress = null) => ComputeHash(stream, progress); /// 获取 SHA256 值。 public static byte[] SHA256(this byte[] bytes) => ComputeHash(bytes); /// 获取 SHA256 值。 public static byte[] SHA256(this Stream stream, Action progress = null) => ComputeHash(stream, progress); /// 获取 SHA512 值。 public static byte[] SHA512(this byte[] bytes) => ComputeHash(bytes); /// 获取 SHA512 值。 public static byte[] SHA512(this Stream stream, Action progress = null) => ComputeHash(stream, progress); #endregion } }