diff options
-rw-r--r-- | tool/znk.zig | 76 |
1 files changed, 47 insertions, 29 deletions
diff --git a/tool/znk.zig b/tool/znk.zig index 269e176..e086879 100644 --- a/tool/znk.zig +++ b/tool/znk.zig | |||
@@ -2,7 +2,7 @@ const std = @import("std"); | |||
2 | const Allocator = mem.Allocator; | 2 | const Allocator = mem.Allocator; |
3 | const ascii = std.ascii; | 3 | const ascii = std.ascii; |
4 | const build_options = @import("build_options"); | 4 | const build_options = @import("build_options"); |
5 | const builtin = std.builtin; | 5 | const builtin = @import("builtin"); |
6 | const fs = std.fs; | 6 | const fs = std.fs; |
7 | const io = std.io; | 7 | const io = std.io; |
8 | const mem = std.mem; | 8 | const mem = std.mem; |
@@ -39,17 +39,17 @@ const usage = | |||
39 | pub fn main() anyerror!void { | 39 | pub fn main() anyerror!void { |
40 | var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; | 40 | var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; |
41 | defer std.debug.assert(!general_purpose_allocator.deinit()); | 41 | defer std.debug.assert(!general_purpose_allocator.deinit()); |
42 | const gpa = &general_purpose_allocator.allocator; | 42 | const gpa = general_purpose_allocator.allocator(); |
43 | 43 | ||
44 | var arena_instance = std.heap.ArenaAllocator.init(gpa); | 44 | var arena_instance = std.heap.ArenaAllocator.init(gpa); |
45 | defer arena_instance.deinit(); | 45 | defer arena_instance.deinit(); |
46 | const arena = &arena_instance.allocator; | 46 | const arena = arena_instance.allocator(); |
47 | 47 | ||
48 | const args = try process.argsAlloc(arena); | 48 | const args = try process.argsAlloc(arena); |
49 | return mainArgs(arena, args); | 49 | return mainArgs(arena, args); |
50 | } | 50 | } |
51 | 51 | ||
52 | pub fn mainArgs(arena: *Allocator, args: []const []const u8) !void { | 52 | pub fn mainArgs(arena: Allocator, args: []const []const u8) !void { |
53 | if (args.len <= 1) { | 53 | if (args.len <= 1) { |
54 | info("{s}", .{usage}); | 54 | info("{s}", .{usage}); |
55 | fatal("expected command argument", .{}); | 55 | fatal("expected command argument", .{}); |
@@ -96,7 +96,7 @@ const usage_gen = | |||
96 | \\ | 96 | \\ |
97 | ; | 97 | ; |
98 | 98 | ||
99 | pub fn cmdGen(arena: *Allocator, args: []const []const u8) !void { | 99 | pub fn cmdGen(arena: Allocator, args: []const []const u8) !void { |
100 | const stdin = io.getStdIn(); | 100 | const stdin = io.getStdIn(); |
101 | const stdout = io.getStdOut(); | 101 | const stdout = io.getStdOut(); |
102 | 102 | ||
@@ -200,7 +200,7 @@ const usage_sign = | |||
200 | \\ | 200 | \\ |
201 | ; | 201 | ; |
202 | 202 | ||
203 | pub fn cmdSign(arena: *Allocator, args: []const []const u8) !void { | 203 | pub fn cmdSign(arena: Allocator, args: []const []const u8) !void { |
204 | const stdin = io.getStdIn(); | 204 | const stdin = io.getStdIn(); |
205 | const stdout = io.getStdOut(); | 205 | const stdout = io.getStdOut(); |
206 | 206 | ||
@@ -286,7 +286,7 @@ const usage_verify = | |||
286 | \\ | 286 | \\ |
287 | ; | 287 | ; |
288 | 288 | ||
289 | pub fn cmdVerify(arena: *Allocator, args: []const []const u8) !void { | 289 | pub fn cmdVerify(arena: Allocator, args: []const []const u8) !void { |
290 | const stdin = io.getStdIn(); | 290 | const stdin = io.getStdIn(); |
291 | const stdout = io.getStdOut(); | 291 | const stdout = io.getStdOut(); |
292 | 292 | ||
@@ -391,17 +391,39 @@ pub fn cmdVerify(arena: *Allocator, args: []const []const u8) !void { | |||
391 | try stdout.writeAll("good signature\n"); | 391 | try stdout.writeAll("good signature\n"); |
392 | } | 392 | } |
393 | 393 | ||
394 | const RandomReader = struct { | ||
395 | rand: *const std.rand.Random, | ||
396 | |||
397 | pub const Error = error{}; | ||
398 | pub const Reader = io.Reader(*Self, Error, read); | ||
399 | |||
400 | const Self = @This(); | ||
401 | |||
402 | pub fn init(rand: *const std.rand.Random) Self { | ||
403 | return .{ .rand = rand }; | ||
404 | } | ||
405 | |||
406 | pub fn read(self: *Self, dest: []u8) Error!usize { | ||
407 | self.rand.bytes(dest); | ||
408 | return dest.len; | ||
409 | } | ||
410 | |||
411 | pub fn reader(self: *Self) Reader { | ||
412 | return .{ .context = self }; | ||
413 | } | ||
414 | }; | ||
415 | |||
394 | fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { | 416 | fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { |
395 | return struct { | 417 | return struct { |
396 | role: nkeys.Role, | 418 | role: nkeys.Role, |
397 | prefix: []const u8, | 419 | prefix: []const u8, |
398 | allocator: *Allocator, | 420 | allocator: Allocator, |
399 | done: std.atomic.Atomic(bool), | 421 | done: std.atomic.Atomic(bool), |
400 | entropy: ?EntropyReaderType, | 422 | entropy: ?EntropyReaderType, |
401 | 423 | ||
402 | const Self = @This(); | 424 | const Self = @This(); |
403 | 425 | ||
404 | pub fn init(allocator: *Allocator, role: nkeys.Role, prefix: []const u8, entropy: ?EntropyReaderType) Self { | 426 | pub fn init(allocator: Allocator, role: nkeys.Role, prefix: []const u8, entropy: ?EntropyReaderType) Self { |
405 | return .{ | 427 | return .{ |
406 | .role = role, | 428 | .role = role, |
407 | .prefix = prefix, | 429 | .prefix = prefix, |
@@ -412,28 +434,24 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { | |||
412 | } | 434 | } |
413 | 435 | ||
414 | fn generatePrivate(self: *Self) !void { | 436 | fn generatePrivate(self: *Self) !void { |
415 | while (true) { | 437 | var rr = RandomReader.init(&std.crypto.random); |
416 | if (self.done.load(.SeqCst)) return; | 438 | var brr = io.BufferedReader(1024 * 4096, @TypeOf(rr.reader())){ .unbuffered_reader = rr.reader() }; |
417 | 439 | while (!self.done.load(.SeqCst)) { | |
418 | var gen_result = res: { | 440 | var gen_result = if (self.entropy) |entropy| |
419 | if (self.entropy) |entropy| { | 441 | nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, entropy) |
420 | break :res nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, entropy); | 442 | else |
421 | } else { | 443 | nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, brr.reader()); |
422 | break :res nkeys.SeedKeyPair.generate(self.role); | ||
423 | } | ||
424 | }; | ||
425 | var kp = gen_result catch fatal("could not generate seed", .{}); | 444 | var kp = gen_result catch fatal("could not generate seed", .{}); |
426 | 445 | ||
427 | defer kp.wipe(); | ||
428 | var public_key = kp.publicKeyText(); | 446 | var public_key = kp.publicKeyText(); |
429 | if (!mem.startsWith(u8, public_key[1..], self.prefix)) continue; | 447 | if (mem.startsWith(u8, public_key[1..], self.prefix)) { |
430 | 448 | if (self.done.swap(true, .SeqCst)) return; // another thread is already done | |
431 | if (self.done.swap(true, .SeqCst)) return; // another thread is already done | ||
432 | 449 | ||
433 | info("{s}", .{kp.seedText()}); | 450 | info("{s}", .{kp.seedText()}); |
434 | info("{s}", .{public_key}); | 451 | info("{s}", .{public_key}); |
435 | 452 | ||
436 | return; | 453 | return; |
454 | } | ||
437 | } | 455 | } |
438 | } | 456 | } |
439 | 457 | ||
@@ -444,7 +462,7 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { | |||
444 | } else struct { | 462 | } else struct { |
445 | pub fn generate(self: *Self) !void { | 463 | pub fn generate(self: *Self) !void { |
446 | var cpu_count = try std.Thread.getCpuCount(); | 464 | var cpu_count = try std.Thread.getCpuCount(); |
447 | var threads = try self.allocator.alloc(std.Thread, cpu_count); | 465 | var threads = try self.allocator.alloc(std.Thread, cpu_count*4); |
448 | defer self.allocator.free(threads); | 466 | defer self.allocator.free(threads); |
449 | for (threads) |*thread| thread.* = try std.Thread.spawn(.{}, Self.generatePrivate, .{self}); | 467 | for (threads) |*thread| thread.* = try std.Thread.spawn(.{}, Self.generatePrivate, .{self}); |
450 | for (threads) |thread| thread.join(); | 468 | for (threads) |thread| thread.join(); |
@@ -453,7 +471,7 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { | |||
453 | }; | 471 | }; |
454 | } | 472 | } |
455 | 473 | ||
456 | fn toUpper(allocator: *Allocator, slice: []const u8) ![]u8 { | 474 | fn toUpper(allocator: Allocator, slice: []const u8) ![]u8 { |
457 | const result = try allocator.alloc(u8, slice.len); | 475 | const result = try allocator.alloc(u8, slice.len); |
458 | for (slice) |c, i| result[i] = ascii.toUpper(c); | 476 | for (slice) |c, i| result[i] = ascii.toUpper(c); |
459 | return result; | 477 | return result; |
@@ -519,7 +537,7 @@ pub const Nkey = union(enum) { | |||
519 | } | 537 | } |
520 | }; | 538 | }; |
521 | 539 | ||
522 | pub fn readKeyFile(allocator: *Allocator, file: fs.File) ?Nkey { | 540 | pub fn readKeyFile(allocator: Allocator, file: fs.File) ?Nkey { |
523 | var bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch fatal("could not read key file", .{}); | 541 | var bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch fatal("could not read key file", .{}); |
524 | defer { | 542 | defer { |
525 | for (bytes) |*b| b.* = 0; | 543 | for (bytes) |*b| b.* = 0; |