From 2e5bc609a5a00b325cf64c314fb7b020dbc35cbf Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Sat, 20 Feb 2021 12:12:45 -0500 Subject: [PATCH 1/2] [Added] CreateUserSeed and CreateAccountSeed so these can be generated Signed-off-by: Matthias Hanel --- src/NATS.Client/NKeys.cs | 63 ++++++++++++++++++++++++++++++-- src/Tests/UnitTests/TestNkeys.cs | 56 ++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/Tests/UnitTests/TestNkeys.cs diff --git a/src/NATS.Client/NKeys.cs b/src/NATS.Client/NKeys.cs index 79f0ebfe5..0d479f453 100644 --- a/src/NATS.Client/NKeys.cs +++ b/src/NATS.Client/NKeys.cs @@ -12,6 +12,8 @@ // limitations under the License. using NATS.Client.NaCl; using System; +using System.IO; +using System.Text; namespace NATS.Client { @@ -231,8 +233,7 @@ public static void Wipe(string src) src.Remove(0); } - - private static byte[] DecodeSeed(byte[] raw) + internal static byte[] DecodeSeed(byte[] raw) { // Need to do the reverse here to get back to internal representation. byte b1 = (byte)(raw[0] & 248); // 248 = 11111000 @@ -261,7 +262,7 @@ private static byte[] DecodeSeed(byte[] raw) } } - private static byte[] DecodeSeed(string src) + internal static byte[] DecodeSeed(string src) { return DecodeSeed(Nkeys.Decode(src)); } @@ -271,7 +272,7 @@ private static byte[] DecodeSeed(string src) /// /// /// A NATS Ed25519 Keypair - static public NkeyPair FromSeed(string seed) + public static NkeyPair FromSeed(string seed) { byte[] userSeed = DecodeSeed(seed); try @@ -284,5 +285,59 @@ static public NkeyPair FromSeed(string seed) Wipe(ref userSeed); } } + + internal static string EncodeSeed(byte prefixbyte, byte[] src) + { + if (!IsValidPublicPrefixByte(prefixbyte)) + throw new NATSException("Invalid prefix"); + + if (src.Length != 32) + throw new NATSException("Invalid seed size"); + + // In order to make this human printable for both bytes, we need to do a little + // bit manipulation to setup for base32 encoding which takes 5 bits at a time. + byte b1 = (byte) (PrefixByteSeed | (prefixbyte >> 5)); + byte b2 = (byte) ((prefixbyte & 31) << 3); // 31 = 00011111 + + MemoryStream stream = new MemoryStream(); + stream.WriteByte(b1); + stream.WriteByte(b2); + + // write payload + stream.Write(src, 0, src.Length); + + // Calculate and write crc16 checksum + byte[] checksum = BitConverter.GetBytes(Crc16.Checksum(stream.ToArray())); + stream.Write(checksum, 0, checksum.Length); + + return Base32.Encode(stream.ToArray()); + } + + private static string CreateSeed(byte prefixbyte) { + byte[] rawSeed = new byte[32]; + + Random rnd = new Random(); + rnd.NextBytes(rawSeed); + + return EncodeSeed(prefixbyte, rawSeed); + } + + /// + /// Creates a private user seed String. + /// + /// A NATS Ed25519 User Seed + public static string CreateUserSeed() + { + return CreateSeed(PrefixByteUser); + } + + /// + /// Creates a private account seed String. + /// + /// A NATS Ed25519 Account Seed + public static string CreateAccountSeed() + { + return CreateSeed(PrefixByteAccount); + } } } diff --git a/src/Tests/UnitTests/TestNkeys.cs b/src/Tests/UnitTests/TestNkeys.cs new file mode 100644 index 000000000..263b0161b --- /dev/null +++ b/src/Tests/UnitTests/TestNkeys.cs @@ -0,0 +1,56 @@ +// Copyright 2021-2021 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using NATS.Client; +using Xunit; + +namespace UnitTests +{ +#pragma warning disable CS0618 + public class TestNkeys + { + [Fact] + public void TestNKEYEncodeDecode() + { + byte[] a = new Byte[32]; + byte[] b = Nkeys.DecodeSeed( Nkeys.EncodeSeed(20 << 3, a)); + Assert.Equal(a, b); + + Random rnd = new Random(); + rnd.NextBytes(a); + b = Nkeys.DecodeSeed( Nkeys.EncodeSeed(20 << 3, a)); + Assert.Equal(a, b); + } + + [Fact] + public void TestNKEYCreateUserSeed() + { + string user = Nkeys.CreateUserSeed(); + Assert.NotEmpty(user); + NkeyPair uk = Nkeys.FromSeed(user); + Assert.NotNull(uk); + } + + [Fact] + public void TestNKEYCreateAccountSeed() + { + string acc = Nkeys.CreateAccountSeed(); + Assert.NotEmpty(acc); + NkeyPair uk = Nkeys.FromSeed(acc); + Assert.NotNull(uk); + } + } + +#pragma warning restore CS0618 +} \ No newline at end of file From a0a2f1a6c1edef33ad1bb6a2b9f8c483792426d0 Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Sun, 21 Feb 2021 19:07:18 -0500 Subject: [PATCH 2/2] Incorporating review comments added seed generation for operator + unit test Signed-off-by: Matthias Hanel --- src/NATS.Client/NKeys.cs | 9 +++++++++ src/Tests/UnitTests/TestNkeys.cs | 16 +++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/NATS.Client/NKeys.cs b/src/NATS.Client/NKeys.cs index 0d479f453..0529b302b 100644 --- a/src/NATS.Client/NKeys.cs +++ b/src/NATS.Client/NKeys.cs @@ -339,5 +339,14 @@ public static string CreateAccountSeed() { return CreateSeed(PrefixByteAccount); } + + /// + /// Creates a private operator seed String. + /// + /// A NATS Ed25519 Operator Seed + public static string CreateOperatorSeed() + { + return CreateSeed(PrefixByteOperator); + } } } diff --git a/src/Tests/UnitTests/TestNkeys.cs b/src/Tests/UnitTests/TestNkeys.cs index 263b0161b..d66660640 100644 --- a/src/Tests/UnitTests/TestNkeys.cs +++ b/src/Tests/UnitTests/TestNkeys.cs @@ -38,17 +38,23 @@ public void TestNKEYCreateUserSeed() { string user = Nkeys.CreateUserSeed(); Assert.NotEmpty(user); - NkeyPair uk = Nkeys.FromSeed(user); - Assert.NotNull(uk); + Assert.NotNull(Nkeys.FromSeed(user)); } - + [Fact] public void TestNKEYCreateAccountSeed() { string acc = Nkeys.CreateAccountSeed(); Assert.NotEmpty(acc); - NkeyPair uk = Nkeys.FromSeed(acc); - Assert.NotNull(uk); + Assert.NotNull(Nkeys.FromSeed(acc)); + } + + [Fact] + public void TestNKEYCreateOperatorSeed() + { + string op = Nkeys.CreateOperatorSeed(); + Assert.NotEmpty(op); + Assert.NotNull(Nkeys.FromSeed(op)); } }