CTR stream cipher mode
This commit is contained in:
parent
c3b3b729ea
commit
733d2d8ef0
2 changed files with 76 additions and 1 deletions
58
src/aes.zig
58
src/aes.zig
|
@ -6,12 +6,13 @@ const xor = @import("xor.zig");
|
|||
const base64 = @import("base64.zig");
|
||||
const padding = @import("padding.zig");
|
||||
|
||||
pub const Mode = enum { ECB, CBC };
|
||||
pub const Mode = enum { ECB, CBC, CTR };
|
||||
|
||||
pub const AES = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
key: []const u8,
|
||||
iv: ?[]const u8 = null,
|
||||
nonce: ?u64 = null,
|
||||
nettle_ctx: nettle.struct_aes_ctx,
|
||||
mode: Mode,
|
||||
|
||||
|
@ -59,6 +60,23 @@ pub const AES = struct {
|
|||
return aes;
|
||||
}
|
||||
|
||||
pub fn init_ctr(allocator: std.mem.Allocator, key: []const u8, nonce: u64) AES {
|
||||
const owned_key = allocator.dupe(u8, key) catch {
|
||||
@panic("Could not allocate key memory");
|
||||
};
|
||||
errdefer allocator.free(owned_key);
|
||||
|
||||
const aes = AES{
|
||||
.allocator = allocator,
|
||||
.key = owned_key,
|
||||
.nettle_ctx = nettle.struct_aes_ctx{},
|
||||
.mode = Mode.CTR,
|
||||
.nonce = nonce,
|
||||
};
|
||||
|
||||
return aes;
|
||||
}
|
||||
|
||||
/// Encrypt buffer `buf`. Must be integer multiple of keysize.
|
||||
/// Caller must free result.
|
||||
pub fn encrypt(self: *@This(), allocator: std.mem.Allocator, buf: []const u8) ![]u8 {
|
||||
|
@ -67,6 +85,7 @@ pub const AES = struct {
|
|||
switch (self.mode) {
|
||||
.ECB => return self.encrypt_ecb(allocator, buf),
|
||||
.CBC => return self.encrypt_cbc(allocator, buf),
|
||||
.CTR => return self.encrypt_ctr(allocator, buf),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +123,41 @@ pub const AES = struct {
|
|||
return enc;
|
||||
}
|
||||
|
||||
fn encrypt_ctr(self: @This(), allocator: std.mem.Allocator, buf: []const u8) ![]u8 {
|
||||
const enc = try allocator.alloc(u8, buf.len);
|
||||
errdefer allocator.free(enc);
|
||||
|
||||
const nonce = self.nonce.?;
|
||||
var counter: u64 = 0;
|
||||
|
||||
const block_size = self.key.len;
|
||||
var block_idx: usize = 0;
|
||||
|
||||
const ctr_block = try allocator.alloc(u8, 16);
|
||||
defer allocator.free(ctr_block);
|
||||
|
||||
const enc_buf = try allocator.alloc(u8, 16);
|
||||
defer allocator.free(enc_buf);
|
||||
|
||||
var it = std.mem.window(u8, buf, block_size, block_size);
|
||||
|
||||
while (it.next()) |block| {
|
||||
@memcpy(ctr_block[0..8], &@as([8]u8, @bitCast(nonce)));
|
||||
@memcpy(ctr_block[8..], &@as([8]u8, @bitCast(counter)));
|
||||
|
||||
nettle.aes_encrypt(&self.nettle_ctx, block_size, enc_buf.ptr, ctr_block.ptr);
|
||||
|
||||
for (0..block.len) |i| {
|
||||
enc[block_idx + i] = block[i] ^ enc_buf[i];
|
||||
}
|
||||
|
||||
block_idx += block.len;
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
/// Decrypt buffer `buf`. Must be integer multiple of keysize.
|
||||
/// Caller must free result.
|
||||
pub fn decrypt(self: *@This(), allocator: std.mem.Allocator, buf: []const u8) ![]u8 {
|
||||
|
@ -112,6 +166,7 @@ pub const AES = struct {
|
|||
switch (self.mode) {
|
||||
.ECB => return self.decrypt_ecb(allocator, buf),
|
||||
.CBC => return self.decrypt_cbc(allocator, buf),
|
||||
.CTR => return self.encrypt(allocator, buf),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +241,7 @@ pub const ECB_CBC_Oracle = struct {
|
|||
var cipher = switch (self.mode) {
|
||||
.ECB => AES.init_ecb(self.alloc, key),
|
||||
.CBC => AES.init_cbc(self.alloc, key, iv),
|
||||
.CTR => @panic("No CTR Oracle available"),
|
||||
};
|
||||
defer cipher.deinit();
|
||||
|
||||
|
|
19
src/main.zig
19
src/main.zig
|
@ -91,6 +91,10 @@ pub fn main() !void {
|
|||
if (std.mem.eql(u8, args[1], "s3c17")) {
|
||||
try s3c17(allocator, stdout);
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, args[1], "s3c18")) {
|
||||
try s3c18(allocator, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
fn s1c1(allocator: std.mem.Allocator, stdout: anytype) !void {
|
||||
|
@ -471,3 +475,18 @@ fn s3c17(allocator: std.mem.Allocator, stdout: anytype) !void {
|
|||
|
||||
try stdout.print("Cracked secret: \n\t{s}\nClear text: \n\t{s}\n", .{ secret_encoded, result });
|
||||
}
|
||||
|
||||
fn s3c18(allocator: std.mem.Allocator, stdout: anytype) !void {
|
||||
const secret = "L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==";
|
||||
|
||||
const secret_decoded = try b64.decode(allocator, secret);
|
||||
defer allocator.free(secret_decoded);
|
||||
|
||||
var cipher = aes.AES.init_ctr(allocator, "YELLOW SUBMARINE", 0);
|
||||
defer cipher.deinit();
|
||||
|
||||
const clear_text = try cipher.decrypt(allocator, secret_decoded);
|
||||
defer allocator.free(clear_text);
|
||||
|
||||
try stdout.print("Clear text:\n{s}\n", .{clear_text});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue