diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nkeys.zig | 94 |
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 | ||
| 87 | const binary_private_size = 1 + Ed25519.secret_length + 2; | ||
| 88 | // One prefix byte, two CRC bytes | ||
| 89 | const binary_public_size = 1 + Ed25519.public_length + 2; | ||
| 90 | // Two prefix bytes, two CRC bytes | ||
| 91 | const binary_seed_size = 2 + Ed25519.seed_length + 2; | ||
| 92 | |||
| 93 | pub const text_private_len = base32.Encoder.calcSize(binary_private_size); | ||
| 94 | pub const text_public_len = base32.Encoder.calcSize(binary_public_size); | ||
| 95 | pub const text_seed_len = base32.Encoder.calcSize(binary_seed_size); | ||
| 96 | |||
| 97 | pub const text_private = [text_private_len]u8; | ||
| 98 | pub const text_public = [text_public_len]u8; | ||
| 99 | pub const text_seed = [text_seed_len]u8; | ||
| 100 | |||
| 86 | pub const SeedKeyPair = struct { | 101 | pub 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 | ||
| 171 | fn wipeKeyPair(kp: *Ed25519.KeyPair) void { | ||
| 172 | wipeBytes(&kp.public_key); | ||
| 173 | wipeBytes(&kp.secret_key); | ||
| 174 | } | ||
| 175 | |||
| 176 | fn wipeBytes(bs: []u8) void { | ||
| 177 | for (bs) |*b| b.* = 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | pub const PublicKey = struct { | 186 | pub 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 | ||
| 276 | const binary_private_size = 1 + Ed25519.secret_length + 2; | ||
| 277 | // One prefix byte, two CRC bytes | ||
| 278 | const binary_public_size = 1 + Ed25519.public_length + 2; | ||
| 279 | // Two prefix bytes, two CRC bytes | ||
| 280 | const binary_seed_size = 2 + Ed25519.seed_length + 2; | ||
| 281 | |||
| 282 | pub const text_private_len = base32.Encoder.calcSize(binary_private_size); | ||
| 283 | pub const text_public_len = base32.Encoder.calcSize(binary_public_size); | ||
| 284 | pub const text_seed_len = base32.Encoder.calcSize(binary_seed_size); | ||
| 285 | |||
| 286 | pub const text_private = [text_private_len]u8; | ||
| 287 | pub const text_public = [text_public_len]u8; | ||
| 288 | pub const text_seed = [text_seed_len]u8; | ||
| 289 | |||
| 290 | fn encoded_key(comptime prefix_len: usize, comptime data_len: usize) type { | 281 | fn 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 | ||
| 432 | fn validNkey(text: []const u8) bool { | 423 | pub 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 | |||
| 436 | pub 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 | |||
| 443 | fn 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 | ||
| 455 | pub fn parseDecoratedNkey(contents: []const u8) NoNkeySeedFoundError!SeedKeyPair { | 466 | fn 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 | ||
| 468 | pub fn parseDecoratedUserNkey(contents: []const u8) (NoNkeySeedFoundError || NoNkeyUserSeedFoundError)!SeedKeyPair { | 471 | fn 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 | ||
| 475 | test { | 475 | test { |