You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1033 lines
38 KiB

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
{
/// <summary>二进制。</summary>
public class BinaryUtility
{
/// <summary>空字节数组,每次获取都将创建新的引用。</summary>
public static byte[] EmptyBytes { get => new byte[0]; }
#region ASCII
/// <summary>CRLF。</summary>
public static byte[] CRLF { get => new byte[] { 13, 10 }; }
/// <summary>0x00 空字符。</summary>
public static byte[] NULL { get => new byte[] { 0x00 }; }
#endregion
#region Bytes Array
/// <summary>克隆字节数组。当源为 NULL 时获取零元素字节数组。</summary>
public static byte[] Clone(byte[] bytes)
{
if (bytes == null || bytes.LongLength < 0L) return EmptyBytes;
var result = new byte[bytes.LongLength];
bytes.CopyTo(result, 0L);
return result;
}
/// <summary>创建数组,元素值为零。</summary>
public static byte[] ZeroArray(int length = 0)
{
if (length < 1) return new byte[0];
var array = new byte[length];
for (int i = 0; i < length; i++) array[i] = 0;
return array;
}
/// <summary>所有字节取反。</summary>
public static byte[] Adverse(byte[] bytes)
{
if (bytes == null || bytes.LongLength < 1L) return EmptyBytes;
var adverse = new byte[bytes.LongLength];
for (var i = 0L; i < bytes.LongLength; i++) adverse[i] = Convert.ToByte(255 - bytes[i]);
return adverse;
}
/// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
public static bool StartsWith(byte[] bytes, params byte[] head)
{
var data = bytes;
if (data == null) return false;
if (head == null) return false;
var datalength = data.LongLength;
var headlength = head.LongLength;
if (datalength < headlength) return false;
if (headlength < 1L) return true;
for (long i = 0; i < head.LongLength; i++)
{
if (data[i] != head[i]) return false;
}
return true;
}
/// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
public static bool EndsWith(byte[] bytes, params byte[] end)
{
if (bytes == null) return false;
if (end == null) return false;
var dataLength = bytes.LongLength;
var endLength = end.LongLength;
if (dataLength < endLength) return false;
if (endLength < 1L) return true;
for (long i = 0; i < endLength; i++)
{
var dataindex = dataLength - i - 1;
var headindex = endLength - i - 1;
if (bytes[dataindex] != end[headindex]) return false;
}
return true;
}
/// <summary>合并字节数组。</summary>
public static byte[] Merge(IEnumerable<byte[]> array)
{
if (array == null) return EmptyBytes;
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;
}
/// <summary>合并字节数组。</summary>
public static byte[] Merge(params byte[][] array) => Merge(array as IEnumerable<byte[]>);
/// <summary>为字节数组增加字节。</summary>
public static byte[] Append(byte[] head, params byte[] bytes) => Merge(head, bytes);
/// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
public static byte[] AddTextBom(params 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);
}
/// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
public static byte[] WipeTextBom(byte[] bytes)
{
if (bytes == null) return EmptyBytes;
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;
}
/// <summary>生成新的 GUID 数据。</summary>
public static byte[] NewGuid() => Guid.NewGuid().ToByteArray();
#endregion
#region Text
/// <summary>将字节数组转换为十六进制文本。</summary>
public static string ToHex(params 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 "";
}
/// <summary>将十六进制文本转换为字节数组。</summary>
public static byte[] FromHex(string hex)
{
if (string.IsNullOrEmpty(hex) || hex.Length < 2) return EmptyBytes;
if (hex.Length % 2 != 0) return EmptyBytes;
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 EmptyBytes;
bytes[i] = Convert.ToByte((h * 16) + l);
}
return bytes;
}
/// <summary>将字节数组格式化为大写十六进制字符串。</summary>
public static string ToX2(params byte[] bytes)
{
if (bytes == null) return "";
var sb = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
sb.Append(bytes[i].ToString("X2"));
}
return sb.ToString();
}
/// <summary>Byte[] -> Base64</summary>
public static string ToBase64(params byte[] bytes)
{
if (bytes.Length < 1) return Constant.EmptyString;
try { return Convert.ToBase64String(bytes); }
catch { return Constant.EmptyString; }
}
/// <summary>Base64 -> Byte[]</summary>
public static byte[] FromBase64(string base64)
{
if (string.IsNullOrEmpty(base64)) return EmptyBytes;
try { return Convert.FromBase64String(base64); }
catch { return EmptyBytes; }
}
/// <summary>转换字节数组为文本,默认使用 UTF-8 代码页。</summary>
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; }
}
/// <summary>转换文本为字节数组,默认使用 UTF-8 代码页。</summary>
public static byte[] FromText(string text, Encoding encoding = null)
{
if (string.IsNullOrEmpty(text)) return EmptyBytes;
try { return (encoding ?? Encoding.UTF8).GetBytes(text); }
catch { return EmptyBytes; }
}
/// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
public static bool ContainsBOM(byte[] bytes)
{
if (bytes == null) return false;
if (bytes.LongLength < 3L) return false;
return bytes[0L] == 0xEF && bytes[1L] == 0xBB && bytes[2L] == 0xBF;
}
/// <summary>检查字节数组是 UTF-8 文本。可指定检查的最大字节长度。</summary>
/// <param name="bytes">要检查的字节数组。</param>
/// <param name="offset">已检查的偏移量。</param>
/// <param name="checkLength">检查的最大字节长度。</param>
public static bool IsUTF8(byte[] bytes, Class<int> offset, int checkLength = 1048576)
{
return IsUTF8(bytes, offset, checkLength);
}
/// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
/// <param name="bytes">要检查的字节数组。</param>
/// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
/// <param name="offset">已检查的偏移量,用于调试。</param>
public static bool IsUTF8(byte[] bytes, int checkLength = 1048576, Class<int> offset = null)
{
// UTF8在Unicode的基础上制定了这样一套规则:
// 1.对于单字节字符,比特位的最高位为0;
// 2.对于多字节字符,第一个字节的比特位中,最高位有n个1,剩下的n - 1个字节的比特位中,最高位都是10。
// 好了,我知道你一定看不懂,那就先来看看下面例子后,再去看上面定义吧。
// 比如一个字符(“A”),它在UTF8中的编码为(用二进制表示):01000001。由于比特位的最高位是0,表示它是单字节,它只需要1个字节就可以表示。
// 再比如一个字符(“判”),它在UTF8中的编码为(用二进制表示):11100101 10001000 10100100。由于在第一个字节中,比特位最高位有3个1,说明这个字符总共需要3个字节来表示,且后3 - 1 = 2位字节中,比特位的最高位为10。
if (bytes == null) return false;
var length = bytes.LongLength;
// 检查 BOM 头。
if (ContainsBOM(bytes)) return true;
var hasOffset = offset != null;
var append = 0;
if (hasOffset) offset.Value = 0;
for (int i = 0; i < length; i++)
{
if (checkLength > 0 && i >= checkLength) break;
var b = bytes[i];
if (hasOffset) offset.Value = i;
// 追加字节最高位为 0。
if (append > 0)
{
if (b >> 6 != 2) return false;
append -= 1;
continue;
}
// ASCII 字符。
if (b < 128) continue;
// 2 字节 UTF-8。
if (b >= 0xC0 && b <= 0xDF)
{
append = 1;
continue;
}
// 3 字节 UTF-8 字符。
if (b >= 0xE0 && b <= 0xEF)
{
append = 2;
continue;
}
// 4 字节 UTF-8 字符。
if (b >= 0xF0 && b <= 0xF7)
{
append = 3;
continue;
}
// 5 字节 UTF-8 字符。
if (b >= 0xF8 && b <= 0xFB)
{
append = 4;
continue;
}
// 6 字节 UTF-8 字符。
if (b >= 0xFC && b <= 0xFD)
{
append = 5;
continue;
}
// 未知字节,非 UTF-8 定义。
return false;
}
return true;
}
#endregion
#region 压缩、解压。
/// <summary>对数据进行 GZip 压缩。</summary>
public static byte[] ToGzip(byte[] plain)
{
if (plain == null || plain.Length == 0) return EmptyBytes;
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;
}
/// <summary>对数据进行 GZip 解压。</summary>
public static byte[] FromGzip(byte[] gzip)
{
if (gzip == null || gzip.Length == 0) return EmptyBytes;
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;
}
/// <summary>压缩字典为 ZIP 文件。</summary>
/// <param name="files">由文件名和文件内容组成的字典。</param>
/// <param name="target">要输出的 ZIP 流。</param>
public static Exception ToZip(Dictionary<string, byte[]> 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;
}
}
/// <summary>压缩到 ZIP 流。</summary>
/// <param name="names">ZIP 内的文件名。</param>
/// <param name="target">要输出的 ZIP 流。</param>
/// <param name="modifildGetter">获取文件的修改时间。</param>
/// <param name="disposeFiles">释放已写入 ZIP 的输入流。</param>
public static Exception ToZip(IEnumerable<string> names, Stream target, Func<string, Stream> inputGetter, Func<string, DateTime> 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;
}
}
/// <summary>压缩字典为 ZIP 包。</summary>
/// <param name="files">由文件名和文件内容组成的字典。</param>
public static byte[] ToZip(Dictionary<string, byte[]> 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;
}
/// <summary>解压 ZIP 文件。</summary>
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;
}
}
/// <summary>解压 .ZIP 文件为字典。</summary>
public static Dictionary<string, byte[]> FromZip(byte[] zip)
{
var result = new Dictionary<string, byte[]>();
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
/// <summary>关闭,并释放流。</summary>
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 { }
}
}
/// <summary>关闭,并释放流。</summary>
public static void Dispose(IEnumerable<Stream> streams, bool flush = false, bool close = true)
{
if (streams != null)
{
foreach (var stream in streams) Dispose(stream, flush, close);
}
}
/// <summary>重置流的位置到开始位置。</summary>
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;
}
}
/// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
/// <param name="source">要读取的源流。</param>
/// <param name="destination">要写入的目标流。</param>
/// <param name="progress">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
/// <param name="buffer">缓冲区大小,最小值为 1。</param>
/// <returns>已写入的字节数。</returns>
public static long Read(Stream source, Stream destination, Func<long, bool> progress = null, int buffer = 4096)
{
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;
}
/// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
/// <param name="source">要读取的源流。</param>
/// <param name="destination">要写入的目标流。</param>
/// <param name="progress">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
/// <param name="buffer">缓冲区大小,最小值为 1。</param>
/// <returns>已写入的字节数。</returns>
public static long Read(Stream source, Stream destination, Action<long> progress, int buffer = 1024)
{
return Read(source, destination, (x) => { progress?.Invoke(x); return true; }, buffer);
}
/// <summary>读取源流中的数据。</summary>
/// <param name="source">源流。</param>
/// <param name="buffer">缓冲区大小,最小值为 1。</param>
/// <param name="dispose">读取结束后释放源流。</param>
public static byte[] Read(Stream source, int buffer = 1024, 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;
}
/// <summary>读取源流中的数据。</summary>
/// <param name="source">源流。</param>
/// <param name="dispose">读取结束后释放源流。</param>
public static byte[] Read(Stream source, bool dispose) => Read(source, 1024, dispose);
/// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
/// <param name="source">要读取的源流。</param>
/// <param name="destination">要写入的目标流。</param>
/// <param name="writed">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
/// <param name="buffer">缓冲区大小,最小值为 1。</param>
/// <returns>已写入的字节数。</returns>
public static long Read(IEnumerable<Stream> sources, Stream destination, Func<long, bool> writed = null, int buffer = 1024)
{
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;
}
/// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
/// <param name="source">要读取的源流。</param>
/// <param name="destination">要写入的目标流。</param>
/// <param name="writed">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
/// <param name="buffer">缓冲区大小,最小值为 1。</param>
/// <returns>已写入的字节数。</returns>
public static long Read(IEnumerable<Stream> sources, Stream destination, Action<long> writed, int buffer = 1024)
{
return Read(sources, destination, (x) => { writed?.Invoke(x); return true; }, buffer);
}
/// <summary>向目标流写入数据,最多可写入 2147483648 字节。</summary>
public static int Write(Stream destination, byte[] bytes, Action<int> writed, int buffer = 1048576)
{
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(BinaryUtility)}.{nameof(Write)}", ex);
}
return total;
}
/// <summary>向目标流写入数据,最多可写入 2147483647 字节(> 20 GB)。</summary>
public static int Write(Stream destination, params byte[] bytes) => Write(destination, bytes, null);
#endregion
#region AES
private static RijndaelManaged Aes256Provider(byte[] key)
{
var k = key ?? EmptyBytes; // AesFill(key);
var p = new RijndaelManaged();
p.Key = k;
p.Mode = CipherMode.ECB;
p.Padding = PaddingMode.PKCS7;
return p;
}
/// <summary>对数据进行 AES 加密。</summary>
public static byte[] Aes256Encrypt(byte[] bytes, byte[] key = null)
{
if (bytes == null) return EmptyBytes;
if (bytes.Length == 0) return EmptyBytes;
var rm = Aes256Provider(key);
var result = new byte[0];
var ct = rm.CreateEncryptor();
try
{
result = ct.TransformFinalBlock(bytes, 0, bytes.Length);
}
catch { }
return result;
}
/// <summary>对数据进行 AES 解密。</summary>
public static byte[] Aes256Decrypt(byte[] cipher, byte[] key = null)
{
if (cipher == null) return EmptyBytes;
if (cipher.Length == 0) return EmptyBytes;
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;
}
#endregion
#region Hash
private static byte[] ComputeHash<T>(byte[] bytes) where T : HashAlgorithm, new()
{
if (bytes != null)
{
try
{
var algorithm = new T();
var result = algorithm.ComputeHash(bytes);
algorithm.Clear();
#if !NET20
algorithm.Dispose();
#endif
return result;
}
catch { }
}
return EmptyBytes;
}
private static byte[] ComputeHash<T>(Stream stream, bool dispose, Action<long> progress) where T : HashAlgorithm, new()
{
if (progress == null)
{
if (stream != null)
{
var result = EmptyBytes;
try
{
var algorithm = new T();
result = algorithm.ComputeHash(stream);
algorithm.Clear();
#if !NET20
algorithm.Dispose();
#endif
}
catch { }
if (dispose) stream.Dispose();
return result;
}
return EmptyBytes;
}
else
{
if (stream == null) return EmptyBytes;
// 初始化。
var validcallback = progress != null;
var capacity = Constant.DefaultBufferCapacity;
var buffer = new byte[capacity];
var algorithm = new T();
algorithm.Initialize();
// 读取。
var failed = false;
while (true)
{
var read = 0;
try { read = stream.Read(buffer, 0, capacity); }
catch { failed = true; }
if (read < capacity)
{
if (read < 1)
{
algorithm.TransformFinalBlock(new byte[0], 0, 0);
}
else
{
algorithm.TransformFinalBlock(buffer, 0, Convert.ToInt32(read));
}
break;
}
else
{
algorithm.TransformBlock(buffer, 0, Convert.ToInt32(read), buffer, 0);
}
}
if (failed)
{
algorithm.Clear();
#if !NET20
algorithm.Dispose();
#endif
if (dispose) stream.Dispose();
return EmptyBytes;
}
else
{
var result = algorithm.Hash;
algorithm.Clear();
#if !NET20
algorithm.Dispose();
#endif
if (dispose) stream.Dispose();
return result;
}
}
}
/// <summary>获取 MD5 值。</summary>
public static byte[] MD5(params byte[] bytes) => ComputeHash<MD5CryptoServiceProvider>(bytes);
/// <summary>获取 MD5 值。</summary>
public static byte[] MD5(Stream stream, Action<long> progress = null) => ComputeHash<MD5CryptoServiceProvider>(stream, false, progress);
/// <summary>获取 SHA1 值。</summary>
public static byte[] SHA1(params byte[] bytes) => ComputeHash<SHA1CryptoServiceProvider>(bytes);
/// <summary>获取 SHA1 值。</summary>
public static byte[] SHA1(Stream stream, Action<long> progress = null) => ComputeHash<SHA1CryptoServiceProvider>(stream, false, progress);
/// <summary>获取 SHA256 值。</summary>
public static byte[] SHA256(params byte[] bytes) => ComputeHash<SHA256CryptoServiceProvider>(bytes);
/// <summary>获取 SHA256 值。</summary>
public static byte[] SHA256(Stream stream, Action<long> progress = null) => ComputeHash<SHA256CryptoServiceProvider>(stream, false, progress);
/// <summary>获取 SHA512 值。</summary>
public static byte[] SHA512(params byte[] bytes) => ComputeHash<SHA512CryptoServiceProvider>(bytes);
/// <summary>获取 SHA512 值。</summary>
public static byte[] SHA512(Stream stream, Action<long> progress = null) => ComputeHash<SHA512CryptoServiceProvider>(stream, false, progress);
#endregion
}
}