From 522883fa1fcce4880a6dd002ddf4342f6fade3f2 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 9 Feb 2025 17:41:40 +0100 Subject: [PATCH] PKCS#7 padding --- src/main.zig | 14 +++++++ src/padding.zig | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 src/padding.zig diff --git a/src/main.zig b/src/main.zig index 79b7ff0..c44048a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,6 +5,7 @@ const xor = @import("xor.zig"); const xor_crack = @import("xor_crack.zig"); const aes = @import("aes.zig"); const aes_crack = @import("aes_crack.zig"); +const padding = @import("padding.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -46,6 +47,10 @@ pub fn main() !void { if (std.mem.eql(u8, args[1], "s1c8")) { try s1c8(allocator, stdout); } + + if (std.mem.eql(u8, args[1], "s1c9")) { + try s1c9(allocator, stdout); + } } fn s1c1(allocator: std.mem.Allocator, stdout: anytype) !void { @@ -252,3 +257,12 @@ fn s1c8(allocator: std.mem.Allocator, stdout: anytype) !void { lineno += 1; } } + +fn s1c9(allocator: std.mem.Allocator, stdout: anytype) !void { + const input = "YELLOW SUBMARINE"; + + const result = try padding.pkcs7(allocator, input, 20); + defer allocator.free(result); + + try stdout.print("{s}", .{result}); +} diff --git a/src/padding.zig b/src/padding.zig new file mode 100644 index 0000000..cfdda78 --- /dev/null +++ b/src/padding.zig @@ -0,0 +1,99 @@ +const std = @import("std"); + +/// Pad a buffer with PKCS#7. Caller must free result. +pub fn pkcs7(allocator: std.mem.Allocator, buf: []const u8, block_size: u8) ![]u8 { + if (block_size == 0) return error.InvalidBlockSize; + + const diff: u8 = switch (buf.len % block_size) { + 0 => 0, + else => |v| @intCast(block_size - v), + }; + + const out = try allocator.alloc(u8, buf.len + diff); + + std.mem.copyForwards(u8, out, buf); + + for (buf.len..out.len) |i| out[i] = diff; + + return out; +} + +test "pad_oversized_blocksize_with_remainder" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 20); + defer allocator.free(res); + + // 16 byte input, 20 byte blocksize -> padded to 1*20=20 byte with 4 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE\x04\x04\x04\x04", res); +} + +test "pad_triple_oversized_blocksize_with_remainder" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 52); + defer allocator.free(res); + + // 16 byte input, 52 (3*16+4) byte blocksize -> padded to 1*52=52 + // byte with 36 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24", res); +} + +test "pad_exact_blocksize_no_remainder" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 16); + defer allocator.free(res); + + // 16 byte input, 16 byte blocksize -> padded to 1*16=16 byte with + // 0 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE", res); +} + +test "pad_double_blocksize" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 32); + defer allocator.free(res); + + // 16 byte input, 32 byte blocksize -> padded to 1*32=32 byte with + // 16 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10", res); +} + +test "pad_half_blocksize" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 8); + defer allocator.free(res); + + // 16 byte input, 8 byte blocksize -> padded to 2*8=16 byte with 0 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE", res); +} + +test "pad_undersized_blocksize_remainder" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 6); + defer allocator.free(res); + + // 16 byte input, 6 byte blocksize -> padded to 3*6=18 byte with 2 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE\x02\x02", res); +} + +test "pad_max_blocksize" { + const allocator = std.testing.allocator; + + const input = "YELLOW SUBMARINE"; + const res = try pkcs7(allocator, input, 255); + defer allocator.free(res); + + // 16 byte input, 255 byte blocksize -> padded to 1*255=255 byte with 239 byte padding + try std.testing.expectEqualStrings("YELLOW SUBMARINE\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef", res); +}