aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/nkeys.zig94
1 files changed, 47 insertions, 47 deletions
diff --git a/src/nkeys.zig b/src/nkeys.zig
index 42a781f..b7fd520 100644
--- a/src/nkeys.zig
+++ b/src/nkeys.zig
@@ -25,14 +25,14 @@ pub const KeyTypePrefixByte = enum(u8) {
25 seed = 18 << 3, // S 25 seed = 18 << 3, // S
26 private = 15 << 3, // P 26 private = 15 << 3, // P
27 27
28 fn char(self: Self) u8 { 28 pub fn char(self: Self) u8 {
29 return switch (self) { 29 return switch (self) {
30 .seed => 'S', 30 .seed => 'S',
31 .private => 'P', 31 .private => 'P',
32 }; 32 };
33 } 33 }
34 34
35 fn fromChar(c: u8) InvalidPrefixByteError!Self { 35 pub fn fromChar(c: u8) InvalidPrefixByteError!Self {
36 return switch (c) { 36 return switch (c) {
37 'S' => .seed, 37 'S' => .seed,
38 'P' => .private, 38 'P' => .private,
@@ -50,7 +50,7 @@ pub const PublicPrefixByte = enum(u8) {
50 server = 13 << 3, // N 50 server = 13 << 3, // N
51 user = 20 << 3, // U 51 user = 20 << 3, // U
52 52
53 fn fromU8(b: u8) InvalidPrefixByteError!PublicPrefixByte { 53 pub fn fromU8(b: u8) InvalidPrefixByteError!PublicPrefixByte {
54 return switch (b) { 54 return switch (b) {
55 @enumToInt(PublicPrefixByte.server) => .server, 55 @enumToInt(PublicPrefixByte.server) => .server,
56 @enumToInt(PublicPrefixByte.cluster) => .cluster, 56 @enumToInt(PublicPrefixByte.cluster) => .cluster,
@@ -61,7 +61,7 @@ pub const PublicPrefixByte = enum(u8) {
61 }; 61 };
62 } 62 }
63 63
64 fn char(self: Self) u8 { 64 pub fn char(self: Self) u8 {
65 return switch (self) { 65 return switch (self) {
66 .account => 'A', 66 .account => 'A',
67 .cluster => 'C', 67 .cluster => 'C',
@@ -71,7 +71,7 @@ pub const PublicPrefixByte = enum(u8) {
71 }; 71 };
72 } 72 }
73 73
74 fn fromChar(c: u8) InvalidPrefixByteError!Self { 74 pub fn fromChar(c: u8) InvalidPrefixByteError!Self {
75 return switch (c) { 75 return switch (c) {
76 'A' => .account, 76 'A' => .account,
77 'C' => .cluster, 77 'C' => .cluster,
@@ -83,6 +83,21 @@ pub const PublicPrefixByte = enum(u8) {
83 } 83 }
84}; 84};
85 85
86// One prefix byte, two CRC bytes
87const binary_private_size = 1 + Ed25519.secret_length + 2;
88// One prefix byte, two CRC bytes
89const binary_public_size = 1 + Ed25519.public_length + 2;
90// Two prefix bytes, two CRC bytes
91const binary_seed_size = 2 + Ed25519.seed_length + 2;
92
93pub const text_private_len = base32.Encoder.calcSize(binary_private_size);
94pub const text_public_len = base32.Encoder.calcSize(binary_public_size);
95pub const text_seed_len = base32.Encoder.calcSize(binary_seed_size);
96
97pub const text_private = [text_private_len]u8;
98pub const text_public = [text_public_len]u8;
99pub const text_seed = [text_seed_len]u8;
100
86pub const SeedKeyPair = struct { 101pub const SeedKeyPair = struct {
87 const Self = @This(); 102 const Self = @This();
88 103
@@ -168,15 +183,6 @@ pub const SeedKeyPair = struct {
168 } 183 }
169}; 184};
170 185
171fn wipeKeyPair(kp: *Ed25519.KeyPair) void {
172 wipeBytes(&kp.public_key);
173 wipeBytes(&kp.secret_key);
174}
175
176fn wipeBytes(bs: []u8) void {
177 for (bs) |*b| b.* = 0;
178}
179
180pub const PublicKey = struct { 186pub const PublicKey = struct {
181 const Self = @This(); 187 const Self = @This();
182 188
@@ -272,21 +278,6 @@ pub const PrivateKey = struct {
272 } 278 }
273}; 279};
274 280
275// One prefix byte, two CRC bytes
276const binary_private_size = 1 + Ed25519.secret_length + 2;
277// One prefix byte, two CRC bytes
278const binary_public_size = 1 + Ed25519.public_length + 2;
279// Two prefix bytes, two CRC bytes
280const binary_seed_size = 2 + Ed25519.seed_length + 2;
281
282pub const text_private_len = base32.Encoder.calcSize(binary_private_size);
283pub const text_public_len = base32.Encoder.calcSize(binary_public_size);
284pub const text_seed_len = base32.Encoder.calcSize(binary_seed_size);
285
286pub const text_private = [text_private_len]u8;
287pub const text_public = [text_public_len]u8;
288pub const text_seed = [text_seed_len]u8;
289
290fn encoded_key(comptime prefix_len: usize, comptime data_len: usize) type { 281fn encoded_key(comptime prefix_len: usize, comptime data_len: usize) type {
291 return [base32.Encoder.calcSize(prefix_len + data_len + 2)]u8; 282 return [base32.Encoder.calcSize(prefix_len + data_len + 2)]u8;
292} 283}
@@ -429,7 +420,27 @@ pub fn parseDecoratedJwt(contents: []const u8) []const u8 {
429 return findKeySection(contents, &line_it) orelse return contents; 420 return findKeySection(contents, &line_it) orelse return contents;
430} 421}
431 422
432fn validNkey(text: []const u8) bool { 423pub fn parseDecoratedNkey(contents: []const u8) NoNkeySeedFoundError!SeedKeyPair {
424 var line_it = mem.split(contents, "\n");
425 var current_off: usize = 0;
426 var seed: ?[]const u8 = null;
427 if (findKeySection(contents, &line_it) != null)
428 seed = findKeySection(contents, &line_it);
429 if (seed == null)
430 seed = findNkey(contents) orelse return error.NoNkeySeedFound;
431 if (!isValidCredsNkey(seed.?))
432 return error.NoNkeySeedFound;
433 return SeedKeyPair.fromTextSeed(seed.?[0..text_seed_len]) catch return error.NoNkeySeedFound;
434}
435
436pub fn parseDecoratedUserNkey(contents: []const u8) (NoNkeySeedFoundError || NoNkeyUserSeedFoundError)!SeedKeyPair {
437 var key = try parseDecoratedNkey(contents);
438 if (!mem.startsWith(u8, &key.seedText(), "SU")) return error.NoNkeyUserSeedFound;
439 defer key.wipe();
440 return key;
441}
442
443fn isValidCredsNkey(text: []const u8) bool {
433 const valid_prefix = 444 const valid_prefix =
434 mem.startsWith(u8, text, "SO") or 445 mem.startsWith(u8, text, "SO") or
435 mem.startsWith(u8, text, "SA") or 446 mem.startsWith(u8, text, "SA") or
@@ -444,7 +455,7 @@ fn findNkey(text: []const u8) ?[]const u8 {
444 while (line_it.next()) |line| { 455 while (line_it.next()) |line| {
445 for (line) |c, i| { 456 for (line) |c, i| {
446 if (!ascii.isSpace(c)) { 457 if (!ascii.isSpace(c)) {
447 if (validNkey(line[i..])) return line[i..]; 458 if (isValidCredsNkey(line[i..])) return line[i..];
448 break; 459 break;
449 } 460 }
450 } 461 }
@@ -452,24 +463,13 @@ fn findNkey(text: []const u8) ?[]const u8 {
452 return null; 463 return null;
453} 464}
454 465
455pub fn parseDecoratedNkey(contents: []const u8) NoNkeySeedFoundError!SeedKeyPair { 466fn wipeKeyPair(kp: *Ed25519.KeyPair) void {
456 var line_it = mem.split(contents, "\n"); 467 wipeBytes(&kp.public_key);
457 var current_off: usize = 0; 468 wipeBytes(&kp.secret_key);
458 var seed: ?[]const u8 = null;
459 if (findKeySection(contents, &line_it) != null)
460 seed = findKeySection(contents, &line_it);
461 if (seed == null)
462 seed = findNkey(contents) orelse return error.NoNkeySeedFound;
463 if (!validNkey(seed.?))
464 return error.NoNkeySeedFound;
465 return SeedKeyPair.fromTextSeed(seed.?[0..text_seed_len]) catch return error.NoNkeySeedFound;
466} 469}
467 470
468pub fn parseDecoratedUserNkey(contents: []const u8) (NoNkeySeedFoundError || NoNkeyUserSeedFoundError)!SeedKeyPair { 471fn wipeBytes(bs: []u8) void {
469 var key = try parseDecoratedNkey(contents); 472 for (bs) |*b| b.* = 0;
470 if (!mem.startsWith(u8, &key.seedText(), "SU")) return error.NoNkeyUserSeedFound;
471 defer key.wipe();
472 return key;
473} 473}
474 474
475test { 475test {