(bugfix): add remove padding, code review

This commit is contained in:
Maksym Sadovnychyy 2024-11-03 06:08:18 -08:00
parent 225debf8f2
commit fcbf7e17b5
5 changed files with 164 additions and 179 deletions

View File

@ -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) {
PathAccessWrapper(workingFolder, (directoryPath) => {
@ -334,7 +314,7 @@ public class Application {
var encryptedDescriptorData = AESGCMUtility.EncryptData(descriptorData, _secret);
// 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
var descriptorBlocks = (paddedDescriptorData.Length + blockSize - 1) / blockSize;
@ -381,55 +361,53 @@ public class Application {
handler.SetPosition(TapeDeviceHandler.TAPE_SPACE_FILEMARKS, 0, 1);
Thread.Sleep(2000);
var position = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
if (position.Error != null)
var endOfBackupMarkerPosition = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
if (endOfBackupMarkerPosition.Error != null || endOfBackupMarkerPosition.OffsetLow == 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);
Thread.Sleep(2000);
position = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
if (position.Error != null)
var endOfDescriptorMarkerPosition = handler.GetPosition(TapeDeviceHandler.TAPE_ABSOLUTE_BLOCK);
if (endOfDescriptorMarkerPosition.Error != null || endOfDescriptorMarkerPosition.OffsetLow == 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);
// read data from descriptorBlocks
var buffer = new List<byte>();
for (var i = 0; i < desctiptorBlocks; i++) {
var data = handler.ReadData(blockSize);
buffer.AddRange(data);
descriptorBlocks -= 2;
var paddedData = new byte[(descriptorBlocks.Value) * blockSize];
var buffer = new byte[blockSize];
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
var paddedData = buffer.ToArray();
// i need to remove padding from the data
var encryptedData = PaddingUtility.RemovePadding(paddedData, (int)blockSize);
// Retrieve the padding size from the last byte
int paddingSize = paddedData[^1];
// 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);
// decrypt the data
var decryptedData = AESGCMUtility.DecryptData(encryptedData, _secret);
// Convert byte array to string and trim ending zeros
var json = Encoding.UTF8.GetString(descriptorData);
var json = Encoding.UTF8.GetString(decryptedData);
try {
var descriptor = JsonSerializer.Deserialize<BackupDescriptor>(json);
@ -514,7 +492,7 @@ public class Application {
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;

View 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)
];
}

View File

@ -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}");
}
}
}
}

View File

@ -1,19 +1,16 @@
using System.IO;
using System.Security.Cryptography;
namespace MaksIT.LTO.Core.Helpers;
namespace MaksIT.LTO.Core.Helpers;
public static class ChecksumUtility {
public static string CalculateCRC32Checksum(byte[] data) {
using var crc32 = new Crc32();
byte[] hashBytes = crc32.ComputeHash(data);
var hashBytes = crc32.ComputeHash(data);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
public static string CalculateCRC32ChecksumFromFile(string filePath) {
using var crc32 = new Crc32();
using var stream = File.OpenRead(filePath);
byte[] hashBytes = crc32.ComputeHash(stream);
var hashBytes = crc32.ComputeHash(stream);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
@ -26,105 +23,23 @@ public static class ChecksumUtility {
crc32.TransformBlock(buffer, 0, bytesRead, null, 0);
}
crc32.TransformFinalBlock(buffer, 0, 0);
byte[] hashBytes = crc32.Hash;
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
var hashBytes = crc32.Hash;
return BitConverter.ToString(hashBytes ?? Array.Empty<byte>()).Replace("-", "").ToLower();
}
public static bool VerifyCRC32Checksum(byte[] data, string expectedChecksum) {
string calculatedChecksum = CalculateCRC32Checksum(data);
var calculatedChecksum = CalculateCRC32Checksum(data);
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
}
public static bool VerifyCRC32ChecksumFromFile(string filePath, string expectedChecksum) {
string calculatedChecksum = CalculateCRC32ChecksumFromFile(filePath);
var calculatedChecksum = CalculateCRC32ChecksumFromFile(filePath);
return string.Equals(calculatedChecksum, expectedChecksum, StringComparison.OrdinalIgnoreCase);
}
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);
}
}
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)
];
}

View 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;
}
}