diff --git a/crypto-test/.gitignore b/crypto-test/.gitignore new file mode 100644 index 0000000..7c1baea --- /dev/null +++ b/crypto-test/.gitignore @@ -0,0 +1,5 @@ +.idea/ +zig-out/ +zig-cache/ + +/src/vk.zig diff --git a/crypto-test/build.zig b/crypto-test/build.zig new file mode 100644 index 0000000..3141ec0 --- /dev/null +++ b/crypto-test/build.zig @@ -0,0 +1,83 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const enet_real = b.dependency("enet_real", .{}); + const enet = b.createModule(.{ + .root_source_file = .{ .path = "src/enet.zig" }, + .target = target, + .optimize = optimize, + .link_libc = true, + .sanitize_c = false, + }); + enet.addCSourceFiles(.{ + .root = enet_real.path(""), + .files = &.{ + "callbacks.c", + "compress.c", + "host.c", + "list.c", + "packet.c", + "peer.c", + "protocol.c", + "unix.c", + "win32.c", + }, + }); + enet.addIncludePath(enet_real.path("include")); + + const client = b.addExecutable(.{ + .name = "client", + .root_source_file = .{ .path = "src/client.zig" }, + .target = target, + .optimize = optimize, + }); + client.root_module.addImport("enet", enet); + b.installArtifact(client); + + const server = b.addExecutable(.{ + .name = "server", + .root_source_file = .{ .path = "src/server.zig" }, + .target = target, + .optimize = optimize, + }); + server.root_module.addImport("enet", enet); + b.installArtifact(server); + + const client_cmd = b.addRunArtifact(client); + client_cmd.step.dependOn(b.getInstallStep()); + const server_cmd = b.addRunArtifact(server); + server_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + client_cmd.addArgs(args); + server_cmd.addArgs(args); + } + + const client_step = b.step("client", "Run the client"); + client_step.dependOn(&client_cmd.step); + const server_step = b.step("server", "Run the server"); + server_step.dependOn(&server_cmd.step); + + const client_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/client.zig" }, + .target = target, + .optimize = optimize, + }); + client_tests.root_module.addImport("enet", enet); + const server_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/server.zig" }, + .target = target, + .optimize = optimize, + }); + server_tests.root_module.addImport("enet", enet); + + const run_client_tests = b.addRunArtifact(client_tests); + const run_server_tests = b.addRunArtifact(server_tests); + + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&run_client_tests.step); + test_step.dependOn(&run_server_tests.step); +} diff --git a/crypto-test/build.zig.zon b/crypto-test/build.zig.zon new file mode 100644 index 0000000..6a4662f --- /dev/null +++ b/crypto-test/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .name = "learnzig", + .version = "0.0.0", + + .dependencies = .{ + .enet_real = .{ + .url = "https://github.com/lsalzman/enet/archive/c44b7d0f7ff21edb702745e4c019d0537928c373.tar.gz", + .hash = "1220b65591d2f97033626dfff25a37926b250c7892e812397668769f84ef408cd02e", + }, + }, + + .paths = .{ + "", + }, +} diff --git a/crypto-test/src/client.zig b/crypto-test/src/client.zig new file mode 100644 index 0000000..33a457b --- /dev/null +++ b/crypto-test/src/client.zig @@ -0,0 +1,69 @@ +const std = @import("std"); +const enet = @import("enet"); + +const DH = std.crypto.dh.X25519; +const AES = std.crypto.aead.aes_gcm.Aes256Gcm; +const SHA = std.crypto.hash.sha2.Sha256; + +pub fn main() !void { + if (enet.enet_initialize() != 0) return error.ENetInitFailed; + defer enet.enet_deinitialize(); + + const addr = enet.ENetAddress{ + .host = enet.ENET_HOST_ANY, + .port = enet.ENET_PORT_ANY, + }; + const host = enet.enet_host_create(&addr, 32, 1, 0, 0) orelse return error.ENetHostCreateFailed; + defer enet.enet_host_destroy(host); + + var server_addr = enet.ENetAddress{ + .host = enet.ENET_HOST_ANY, + .port = 9405, + }; + _ = enet.enet_address_set_host(&server_addr, "localhost"); + const peer = enet.enet_host_connect(host, &server_addr, 1, 0); + _ = peer; + + var event: enet.ENetEvent = undefined; + + while (true) { + while (enet.enet_host_service(host, &event, 100) > 0) { + switch (event.type) { + enet.ENET_EVENT_TYPE_CONNECT => { + std.debug.print("client: connected to peer {any}\n", .{event.peer.*.address}); + }, + else => { + std.debug.print("client: other event...\n", .{}); + }, + } + } + } +} + +// it even works in ReleaseFast so I think it's ok. +test "in-place-encrypt" { + const al = std.testing.allocator; + + var key: [AES.key_length]u8 = undefined; + std.crypto.random.bytes(&key); + const iv: [AES.nonce_length]u8 = undefined; + std.crypto.random.bytes(&key); + + var tag: [AES.tag_length]u8 = undefined; + + // 1mb message. very big. should find an error if one exists. + const original_message: []u8 = try al.alloc(u8, 1 << 20); + defer al.free(original_message); + std.crypto.random.bytes(original_message); + + const message = try al.dupe(u8, original_message); + defer al.free(message); + + const ad: []u8 = try al.dupe(u8, "u"); + defer al.free(ad); + + AES.encrypt(message, &tag, message, ad, iv, key); + try std.testing.expect(!std.mem.eql(u8, message, original_message)); + try AES.decrypt(message, message, tag, ad, iv, key); + try std.testing.expect(std.mem.eql(u8, message, original_message)); +} diff --git a/crypto-test/src/enet.zig b/crypto-test/src/enet.zig new file mode 100644 index 0000000..1aa9def --- /dev/null +++ b/crypto-test/src/enet.zig @@ -0,0 +1,7 @@ +const c = @This(); + +pub usingnamespace @cImport({ + @cInclude("enet/enet.h"); +}); + +// todo add "serve" here that invokes some callback with events. diff --git a/crypto-test/src/server.zig b/crypto-test/src/server.zig new file mode 100644 index 0000000..4ed311e --- /dev/null +++ b/crypto-test/src/server.zig @@ -0,0 +1,61 @@ +const std = @import("std"); +const enet = @import("enet"); + +const DH = std.crypto.dh.X25519; +const AES = std.crypto.aead.aes_gcm.Aes256Gcm; +const SHA = std.crypto.hash.sha2.Sha256; + +pub fn main() !void { + if (enet.enet_initialize() != 0) return error.ENetInitFailed; + defer enet.enet_deinitialize(); + + const addr = enet.ENetAddress{ + .host = enet.ENET_HOST_ANY, + .port = 9405, + }; + const host = enet.enet_host_create(&addr, 32, 1, 0, 0) orelse return error.ENetHostCreateFailed; + defer enet.enet_host_destroy(host); + + var event: enet.ENetEvent = undefined; + + while (true) { + while (enet.enet_host_service(host, &event, 100) > 0) { + switch (event.type) { + enet.ENET_EVENT_TYPE_CONNECT => { + std.debug.print("server: connected to peer {any}\n", .{event.peer.*.address}); + }, + else => { + std.debug.print("server: other event...\n", .{}); + }, + } + } + } +} + +// it even works in ReleaseFast so I think it's ok. +test "in-place-encrypt" { + const al = std.testing.allocator; + + var key: [AES.key_length]u8 = undefined; + std.crypto.random.bytes(&key); + const iv: [AES.nonce_length]u8 = undefined; + std.crypto.random.bytes(&key); + + var tag: [AES.tag_length]u8 = undefined; + + // 1mb message. very big. should find an error if one exists. + const original_message: []u8 = try al.alloc(u8, 1 << 20); + defer al.free(original_message); + std.crypto.random.bytes(original_message); + + const message = try al.dupe(u8, original_message); + defer al.free(message); + + const ad: []u8 = try al.dupe(u8, "u"); + defer al.free(ad); + + AES.encrypt(message, &tag, message, ad, iv, key); + try std.testing.expect(!std.mem.eql(u8, message, original_message)); + try AES.decrypt(message, message, tag, ad, iv, key); + try std.testing.expect(std.mem.eql(u8, message, original_message)); +}