(bugfix): add remove padding, code review
This commit is contained in:
parent
225debf8f2
commit
fcbf7e17b5
@ -244,27 +244,7 @@ public class Application {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] AddPadding(byte[] data, int blockSize) {
|
|
||||||
// Calculate the padding size
|
|
||||||
int paddingSize = blockSize - (data.Length % blockSize);
|
|
||||||
if (paddingSize == blockSize) {
|
|
||||||
paddingSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new array with the original data plus padding
|
|
||||||
byte[] paddedData = new byte[data.Length + paddingSize + 1];
|
|
||||||
Array.Copy(data, paddedData, data.Length);
|
|
||||||
|
|
||||||
// Fill the padding with a specific value (e.g., 0x00)
|
|
||||||
for (int i = data.Length; i < paddedData.Length - 1; i++) {
|
|
||||||
paddedData[i] = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the padding size at the end
|
|
||||||
paddedData[paddedData.Length - 1] = (byte)paddingSize;
|
|
||||||
|
|
||||||
return paddedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteFilesToTape(WorkingFolder workingFolder, string descriptorFilePath, uint blockSize) {
|
private void WriteFilesToTape(WorkingFolder workingFolder, string descriptorFilePath, uint blockSize) {
|
||||||
PathAccessWrapper(workingFolder, (directoryPath) => {
|
PathAccessWrapper(workingFolder, (directoryPath) => {
|
||||||
@ -334,7 +314,7 @@ public class Application {
|
|||||||
var encryptedDescriptorData = AESGCMUtility.EncryptData(descriptorData, _secret);
|
var encryptedDescriptorData = AESGCMUtility.EncryptData(descriptorData, _secret);
|
||||||
|
|
||||||
// add padding to the encrypted descriptor data
|
// add padding to the encrypted descriptor data
|
||||||
var paddedDescriptorData = AddPadding(encryptedDescriptorData, (int)blockSize);
|
var paddedDescriptorData = PaddingUtility.AddPadding(encryptedDescriptorData, (int)blockSize);
|
||||||
|
|
||||||
// calculate the number of blocks needed
|
// calculate the number of blocks needed
|
||||||
var descriptorBlocks = (paddedDescriptorData.Length + blockSize - 1) / blockSize;
|
var descriptorBlocks = (paddedDescriptorData.Length + blockSize - 1) / blockSize;
|
||||||
@ -381,55 +361,53 @@ public class Application {
|
|||||||
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 1);
|
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 1);
|
||||||
Thread.Sleep(2000);
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
var position = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
|
var endOfBackupMarkerPosition = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
|
||||||
if (position.Error != null)
|
if (endOfBackupMarkerPosition.Error != null || endOfBackupMarkerPosition.OffsetLow == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var desctiptorBlocks = position.OffsetLow;
|
_logger.LogInformation($"End of backup marker position: {endOfBackupMarkerPosition.OffsetLow}");
|
||||||
|
|
||||||
|
var descriptorBlocks = endOfBackupMarkerPosition.OffsetLow;
|
||||||
|
|
||||||
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 2);
|
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 2);
|
||||||
Thread.Sleep(2000);
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
position = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
|
var endOfDescriptorMarkerPosition = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
|
||||||
if (position.Error != null)
|
if (endOfDescriptorMarkerPosition.Error != null || endOfDescriptorMarkerPosition.OffsetLow == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
desctiptorBlocks = position.OffsetLow - desctiptorBlocks;
|
_logger.LogInformation($"End of descriptor marker position: {endOfDescriptorMarkerPosition.OffsetLow}");
|
||||||
|
|
||||||
|
descriptorBlocks = endOfDescriptorMarkerPosition.OffsetLow - descriptorBlocks;
|
||||||
|
|
||||||
var padding = handler.ReadData(blockSize);
|
if (descriptorBlocks == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 1);
|
_logger.LogInformation($"Descriptor blocks to read: {descriptorBlocks}");
|
||||||
|
|
||||||
|
handler.SetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK, 0, (long)(endOfDescriptorMarkerPosition.OffsetLow - descriptorBlocks));
|
||||||
Thread.Sleep(2000);
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
// read data from descriptorBlocks
|
descriptorBlocks -= 2;
|
||||||
var buffer = new List<byte>();
|
|
||||||
for (var i = 0; i < desctiptorBlocks; i++) {
|
var paddedData = new byte[(descriptorBlocks.Value) * blockSize];
|
||||||
var data = handler.ReadData(blockSize);
|
var buffer = new byte[blockSize];
|
||||||
buffer.AddRange(data);
|
|
||||||
|
for (var i = 0; i < descriptorBlocks; i++) {
|
||||||
|
var bytesRead = handler.ReadData(buffer, 0, buffer.Length);
|
||||||
|
|
||||||
|
// Copy the read data into the encryptedData array
|
||||||
|
Array.Copy(buffer, 0, paddedData, i * blockSize, buffer.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert buffer to array
|
// i need to remove padding from the data
|
||||||
var paddedData = buffer.ToArray();
|
var encryptedData = PaddingUtility.RemovePadding(paddedData, (int)blockSize);
|
||||||
|
|
||||||
// Retrieve the padding size from the last byte
|
// decrypt the data
|
||||||
int paddingSize = paddedData[^1];
|
var decryptedData = AESGCMUtility.DecryptData(encryptedData, _secret);
|
||||||
|
|
||||||
// Calculate the length of the original data
|
|
||||||
int originalDataLength = paddedData.Length - paddingSize - 1;
|
|
||||||
|
|
||||||
// Ensure the padding size is valid
|
|
||||||
if (paddingSize < 0 || paddingSize >= paddedData.Length || originalDataLength < 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Create a new array for the original data
|
|
||||||
var descriptorData = new byte[originalDataLength];
|
|
||||||
Array.Copy(paddedData, descriptorData, originalDataLength);
|
|
||||||
|
|
||||||
descriptorData = AESGCMUtility.DecryptData(descriptorData, _secret);
|
|
||||||
|
|
||||||
// Convert byte array to string and trim ending zeros
|
// Convert byte array to string and trim ending zeros
|
||||||
var json = Encoding.UTF8.GetString(descriptorData);
|
var json = Encoding.UTF8.GetString(decryptedData);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var descriptor = JsonSerializer.Deserialize<BackupDescriptor>(json);
|
var descriptor = JsonSerializer.Deserialize<BackupDescriptor>(json);
|
||||||
@ -514,7 +492,7 @@ public class Application {
|
|||||||
|
|
||||||
var encryptedDescriptorData = AESGCMUtility.EncryptData(File.ReadAllBytes(_descriptorFilePath), _secret);
|
var encryptedDescriptorData = AESGCMUtility.EncryptData(File.ReadAllBytes(_descriptorFilePath), _secret);
|
||||||
|
|
||||||
var paddedDescriptorData = AddPadding(encryptedDescriptorData, (int)descriptor.BlockSize);
|
var paddedDescriptorData = PaddingUtility.AddPadding(encryptedDescriptorData, (int)descriptor.BlockSize);
|
||||||
|
|
||||||
const ulong fileMarkBlocks = 2;
|
const ulong fileMarkBlocks = 2;
|
||||||
|
|
||||||
|
|||||||
87
src/MaksIT.LTO.Core/Crc32.cs
Normal file
87
src/MaksIT.LTO.Core/Crc32.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MaksIT.LTO.Core;
|
||||||
|
|
||||||
|
public class Crc32 : HashAlgorithm {
|
||||||
|
public const uint DefaultPolynomial = 0xedb88320;
|
||||||
|
public const uint DefaultSeed = 0xffffffff;
|
||||||
|
|
||||||
|
private static uint[]? defaultTable;
|
||||||
|
|
||||||
|
private readonly uint seed;
|
||||||
|
private readonly uint[] table;
|
||||||
|
private uint hash;
|
||||||
|
|
||||||
|
public Crc32()
|
||||||
|
: this(DefaultPolynomial, DefaultSeed) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Crc32(uint polynomial, uint seed) {
|
||||||
|
table = InitializeTable(polynomial);
|
||||||
|
this.seed = hash = seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize() {
|
||||||
|
hash = seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void HashCore(byte[] buffer, int start, int length) {
|
||||||
|
hash = CalculateHash(table, hash, buffer, start, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override byte[] HashFinal() {
|
||||||
|
var hashBuffer = UInt32ToBigEndianBytes(~hash);
|
||||||
|
HashValue = hashBuffer;
|
||||||
|
return hashBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int HashSize => 32;
|
||||||
|
|
||||||
|
public static uint Compute(byte[] buffer) {
|
||||||
|
return Compute(DefaultPolynomial, DefaultSeed, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint Compute(uint seed, byte[] buffer) {
|
||||||
|
return Compute(DefaultPolynomial, seed, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint Compute(uint polynomial, uint seed, byte[] buffer) {
|
||||||
|
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint[] InitializeTable(uint polynomial) {
|
||||||
|
if (polynomial == DefaultPolynomial && defaultTable != null)
|
||||||
|
return defaultTable;
|
||||||
|
|
||||||
|
var createTable = new uint[256];
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
var entry = (uint)i;
|
||||||
|
for (var j = 0; j < 8; j++)
|
||||||
|
if ((entry & 1) == 1)
|
||||||
|
entry = (entry >> 1) ^ polynomial;
|
||||||
|
else
|
||||||
|
entry >>= 1;
|
||||||
|
createTable[i] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polynomial == DefaultPolynomial)
|
||||||
|
defaultTable = createTable;
|
||||||
|
|
||||||
|
return createTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint CalculateHash(uint[] table, uint seed, byte[] buffer, int start, int size) {
|
||||||
|
var crc = seed;
|
||||||
|
for (var i = start; i < size - start; i++)
|
||||||
|
crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] UInt32ToBigEndianBytes(uint x) => [
|
||||||
|
(byte)((x >> 24) & 0xff),
|
||||||
|
(byte)((x >> 16) & 0xff),
|
||||||
|
(byte)((x >> 8) & 0xff),
|
||||||
|
(byte)(x & 0xff)
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -1,33 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
|
|
||||||
namespace MaksIT.LTO.Core;
|
|
||||||
public class DriverManager {
|
|
||||||
public static void RestartDriver(string deviceName) {
|
|
||||||
string script = $@"
|
|
||||||
$device = Get-PnpDevice -FriendlyName '{deviceName}'
|
|
||||||
Disable-PnpDevice -InstanceId $device.InstanceId -Confirm:$false
|
|
||||||
Start-Sleep -Seconds 5
|
|
||||||
Enable-PnpDevice -InstanceId $device.InstanceId -Confirm:$false
|
|
||||||
";
|
|
||||||
|
|
||||||
ProcessStartInfo psi = new ProcessStartInfo {
|
|
||||||
FileName = "powershell.exe",
|
|
||||||
Arguments = $"-NoProfile -ExecutionPolicy Bypass -Command \"{script}\"",
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true
|
|
||||||
};
|
|
||||||
|
|
||||||
using (Process process = Process.Start(psi)) {
|
|
||||||
string output = process.StandardOutput.ReadToEnd();
|
|
||||||
string error = process.StandardError.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
Console.WriteLine(output);
|
|
||||||
if (!string.IsNullOrEmpty(error)) {
|
|
||||||
Console.WriteLine($"Error: {error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +1,16 @@
|
|||||||
using System.IO;
|
namespace MaksIT.LTO.Core.Helpers;
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace MaksIT.LTO.Core.Helpers;
|
|
||||||
|
|
||||||
public static class ChecksumUtility {
|
public static class ChecksumUtility {
|
||||||
public static string CalculateCRC32Checksum(byte[] data) {
|
public static string CalculateCRC32Checksum(byte[] data) {
|
||||||
using var crc32 = new Crc32();
|
using var crc32 = new Crc32();
|
||||||
byte[] hashBytes = crc32.ComputeHash(data);
|
var hashBytes = crc32.ComputeHash(data);
|
||||||
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CalculateCRC32ChecksumFromFile(string filePath) {
|
public static string CalculateCRC32ChecksumFromFile(string filePath) {
|
||||||
using var crc32 = new Crc32();
|
using var crc32 = new Crc32();
|
||||||
using var stream = File.OpenRead(filePath);
|
using var stream = File.OpenRead(filePath);
|
||||||
byte[] hashBytes = crc32.ComputeHash(stream);
|
var hashBytes = crc32.ComputeHash(stream);
|
||||||
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,105 +23,23 @@ public static class ChecksumUtility {
|
|||||||
crc32.TransformBlock(buffer, 0, bytesRead, null, 0);
|
crc32.TransformBlock(buffer, 0, bytesRead, null, 0);
|
||||||
}
|
}
|
||||||
crc32.TransformFinalBlock(buffer, 0, 0);
|
crc32.TransformFinalBlock(buffer, 0, 0);
|
||||||
byte[] hashBytes = crc32.Hash;
|
var hashBytes = crc32.Hash;
|
||||||
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
return BitConverter.ToString(hashBytes ?? Array.Empty<byte>()).Replace("-", "").ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyCRC32Checksum(byte[] data, string expectedChecksum) {
|
public static bool VerifyCRC32Checksum(byte[] data, string expectedChecksum) {
|
||||||
string calculatedChecksum = CalculateCRC32Checksum(data);
|
var calculatedChecksum = CalculateCRC32Checksum(data);
|
||||||
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyCRC32ChecksumFromFile(string filePath, string expectedChecksum) {
|
public static bool VerifyCRC32ChecksumFromFile(string filePath, string expectedChecksum) {
|
||||||
string calculatedChecksum = CalculateCRC32ChecksumFromFile(filePath);
|
var calculatedChecksum = CalculateCRC32ChecksumFromFile(filePath);
|
||||||
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyCRC32ChecksumFromFileInChunks(string filePath, string expectedChecksum, int chunkSize = 8192) {
|
public static bool VerifyCRC32ChecksumFromFileInChunks(string filePath, string expectedChecksum, int chunkSize = 8192) {
|
||||||
string calculatedChecksum = CalculateCRC32ChecksumFromFileInChunks(filePath, chunkSize);
|
var calculatedChecksum = CalculateCRC32ChecksumFromFileInChunks(filePath, chunkSize);
|
||||||
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Crc32 : HashAlgorithm {
|
|
||||||
public const uint DefaultPolynomial = 0xedb88320;
|
|
||||||
public const uint DefaultSeed = 0xffffffff;
|
|
||||||
|
|
||||||
private static uint[]? defaultTable;
|
|
||||||
|
|
||||||
private readonly uint seed;
|
|
||||||
private readonly uint[] table;
|
|
||||||
private uint hash;
|
|
||||||
|
|
||||||
public Crc32()
|
|
||||||
: this(DefaultPolynomial, DefaultSeed) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Crc32(uint polynomial, uint seed) {
|
|
||||||
table = InitializeTable(polynomial);
|
|
||||||
this.seed = hash = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize() {
|
|
||||||
hash = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void HashCore(byte[] buffer, int start, int length) {
|
|
||||||
hash = CalculateHash(table, hash, buffer, start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override byte[] HashFinal() {
|
|
||||||
var hashBuffer = UInt32ToBigEndianBytes(~hash);
|
|
||||||
HashValue = hashBuffer;
|
|
||||||
return hashBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int HashSize => 32;
|
|
||||||
|
|
||||||
public static uint Compute(byte[] buffer) {
|
|
||||||
return Compute(DefaultPolynomial, DefaultSeed, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint Compute(uint seed, byte[] buffer) {
|
|
||||||
return Compute(DefaultPolynomial, seed, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint Compute(uint polynomial, uint seed, byte[] buffer) {
|
|
||||||
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint[] InitializeTable(uint polynomial) {
|
|
||||||
if (polynomial == DefaultPolynomial && defaultTable != null)
|
|
||||||
return defaultTable;
|
|
||||||
|
|
||||||
var createTable = new uint[256];
|
|
||||||
for (var i = 0; i < 256; i++) {
|
|
||||||
var entry = (uint)i;
|
|
||||||
for (var j = 0; j < 8; j++)
|
|
||||||
if ((entry & 1) == 1)
|
|
||||||
entry = (entry >> 1) ^ polynomial;
|
|
||||||
else
|
|
||||||
entry >>= 1;
|
|
||||||
createTable[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (polynomial == DefaultPolynomial)
|
|
||||||
defaultTable = createTable;
|
|
||||||
|
|
||||||
return createTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint CalculateHash(uint[] table, uint seed, byte[] buffer, int start, int size) {
|
|
||||||
var crc = seed;
|
|
||||||
for (var i = start; i < size - start; i++)
|
|
||||||
crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] UInt32ToBigEndianBytes(uint x) => [
|
|
||||||
(byte)((x >> 24) & 0xff),
|
|
||||||
(byte)((x >> 16) & 0xff),
|
|
||||||
(byte)((x >> 8) & 0xff),
|
|
||||||
(byte)(x & 0xff)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|||||||
38
src/MaksIT.LTO.Core/Utilities/PaddingUtility.cs
Normal file
38
src/MaksIT.LTO.Core/Utilities/PaddingUtility.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
namespace MaksIT.LTO.Core.Utilities;
|
||||||
|
|
||||||
|
public static class PaddingUtility {
|
||||||
|
|
||||||
|
private const byte _specialByte = 0x80;
|
||||||
|
|
||||||
|
public static byte[] AddPadding(byte[] data, int blockSize) {
|
||||||
|
var paddingSize = blockSize - (data.Length % blockSize);
|
||||||
|
if (paddingSize == blockSize) {
|
||||||
|
paddingSize = 0; // no padding needed if already aligned
|
||||||
|
}
|
||||||
|
|
||||||
|
var paddedData = new byte[data.Length + paddingSize];
|
||||||
|
Array.Copy(data, paddedData, data.Length);
|
||||||
|
|
||||||
|
// fill the padding bytes with specialBytes
|
||||||
|
for (var i = data.Length; i < paddedData.Length; i++) {
|
||||||
|
paddedData[i] = _specialByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paddedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] RemovePadding(byte[] paddedData, int blockSize) {
|
||||||
|
var originalLength = paddedData.Length;
|
||||||
|
|
||||||
|
// find the original length by checking for the padding byte 0x80
|
||||||
|
while (originalLength > 0 && paddedData[originalLength - 1] == _specialByte) {
|
||||||
|
originalLength--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new array to hold the unpadded data
|
||||||
|
var unpaddedData = new byte[originalLength];
|
||||||
|
Array.Copy(paddedData, unpaddedData, originalLength);
|
||||||
|
|
||||||
|
return unpaddedData;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user