(bugfix): add remove padding, code review
This commit is contained in:
		
							parent
							
								
									225debf8f2
								
							
						
					
					
						commit
						8c4da33531
					
				| @ -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; | ||||
|   | ||||
|  | ||||
							
								
								
									
										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; | ||||
| 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) | ||||
|   ]; | ||||
| } | ||||
|  | ||||
							
								
								
									
										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