mirror of
https://github.com/MichaelGrafnetter/DSInternals
synced 2025-01-07 06:30:13 +00:00
135 lines
4.5 KiB
C#
135 lines
4.5 KiB
C#
namespace DSInternals.Common
|
|
{
|
|
using CryptSharp.Utility;
|
|
using System;
|
|
using System.IO;
|
|
using System.Security.Principal;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
public static class ByteArrayExtensions
|
|
{
|
|
private const string hexPattern = "^[0-9a-fA-F]+$";
|
|
|
|
public static void ZeroFill(this byte[] array)
|
|
{
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
array[i] = 0;
|
|
}
|
|
}
|
|
|
|
public static byte[] HexToBinary(this string hex)
|
|
{
|
|
if (string.IsNullOrEmpty(hex))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// CryptSharp does not validate if the input, so we need to do it ourselves.
|
|
bool isHexString = Regex.IsMatch(hex, hexPattern);
|
|
if(!isHexString)
|
|
{
|
|
// TODO: Extract string as resource.
|
|
throw new ArgumentException("Parameter is not a hexadecimal string.");
|
|
}
|
|
|
|
// Finally, do the conversion:
|
|
return Base16Encoding.Hex.GetBytes(hex);
|
|
}
|
|
|
|
public static string ToHex(this byte[] bytes, bool caps = false)
|
|
{
|
|
if (bytes == null)
|
|
{
|
|
return null;
|
|
}
|
|
string hex = Base16Encoding.Hex.GetString(bytes);
|
|
if (caps)
|
|
{
|
|
// Base16Encoding returns uppercase string by default
|
|
return hex;
|
|
}
|
|
else
|
|
{
|
|
return hex.ToLower();
|
|
}
|
|
}
|
|
|
|
public static string ReadWString(this byte[] buffer, int startIndex)
|
|
{
|
|
Validator.AssertNotNull(buffer, "buffer");
|
|
// TODO: Assert startIndex > 0
|
|
int maxLength = buffer.Length - startIndex;
|
|
var sb = new StringBuilder(maxLength);
|
|
for (int i = startIndex; i < buffer.Length; i += UnicodeEncoding.CharSize)
|
|
{
|
|
char c = BitConverter.ToChar(buffer, i);
|
|
if (c == Char.MinValue)
|
|
{
|
|
// End of string reached
|
|
return sb.ToString();
|
|
}
|
|
sb.Append(c);
|
|
}
|
|
// If we reached this point, the \0 char has not been found, so throw an exception.
|
|
// TODO: Add a reasonable exception message
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
public static void SwapBytes(this byte[] bytes, int index1, int index2)
|
|
{
|
|
byte temp = bytes[index1];
|
|
bytes[index1] = bytes[index2];
|
|
bytes[index2] = temp;
|
|
}
|
|
|
|
public static SecurityIdentifier ToSecurityIdentifier(this byte[] binarySid, bool bigEndianRid = false)
|
|
{
|
|
if(binarySid == null)
|
|
{
|
|
return null;
|
|
}
|
|
byte[] output = binarySid;
|
|
if (bigEndianRid)
|
|
{
|
|
// Clone the binary SID so we do not perform byte spapping on the original value.
|
|
byte[] binarySidCopy = (byte[])binarySid.Clone();
|
|
int lastByteIndex = binarySidCopy.Length -1;
|
|
// Convert RID from big endian to little endian (Reverse the order of the last 4 bytes)
|
|
binarySidCopy.SwapBytes(lastByteIndex - 3, lastByteIndex);
|
|
binarySidCopy.SwapBytes(lastByteIndex - 2, lastByteIndex - 1);
|
|
output = binarySidCopy;
|
|
}
|
|
return new SecurityIdentifier(output, 0);
|
|
}
|
|
|
|
public static byte[] Cut(this byte[] blob, int offset)
|
|
{
|
|
Validator.AssertNotNull(blob, "blob");
|
|
return blob.Cut(offset, blob.Length - offset);
|
|
}
|
|
|
|
public static byte[] Cut(this byte[] blob, int offset, int count)
|
|
{
|
|
Validator.AssertNotNull(blob, "blob");
|
|
Validator.AssertMinLength(blob, offset + count, "blob");
|
|
// TODO: Check that offset and count are positive using Validator
|
|
byte[] result = new byte[count];
|
|
Buffer.BlockCopy((Array)blob, offset, (Array)result, 0, count);
|
|
return result;
|
|
}
|
|
|
|
public static byte[] ReadToEnd(this MemoryStream stream)
|
|
{
|
|
long remainingBytes = stream.Length - stream.Position;
|
|
if(remainingBytes > int.MaxValue)
|
|
{
|
|
throw new ArgumentOutOfRangeException("stream");
|
|
}
|
|
byte[] buffer = new byte[remainingBytes];
|
|
stream.Read(buffer, 0, (int)remainingBytes);
|
|
return buffer;
|
|
}
|
|
}
|
|
} |