Skip to content

Commit

Permalink
Use correct seed, don't require entropy source arg for convenience fu…
Browse files Browse the repository at this point in the history
…nctions

Signed-off-by: Derek Collison <derek@nats.io>
  • Loading branch information
derekcollison committed Sep 13, 2018
1 parent b1c20ce commit 56d584c
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 68 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Located under the nk [directory](https://github.com/nats-io/nkeys/tree/master/nk
```go

// Create a new User KeyPair
user, _ := CreateUser(nil) // Can supply an io.Reader for RND.
user, _ := nkeys.CreateUser()

// Sign some data with a full key pair user.
data := []byte("Hello World")
Expand All @@ -42,22 +42,23 @@ sig, _ := user.Sign(data)
err = user.Verify(data, sig)

// Access the seed, the only thing that needs to be stored and kept safe.
// seed = "SUAFXUA5H7BZERZSXYITNDSCBZE7ZZ..."
// seed = "SUAKYRHVIOREXV7EUZTBHUHL7NUMHPMAS7QMDU3GTIUWEI5LDNOXD43IZY"
seed, _ := user.Seed()

// Access the public key which can be shared.
// publicKey = "UAFXUA5H7BZERZSXYITNDSCBZE7ZZ..."
// publicKey = "UD466L6EBCM3YY5HEGHJANNTN4LSKTSUXTH7RILHCKEQMQHTBNLHJJXT"
publicKey, _ := user.PublicKey()

// Create a full User who can sign and verify from a private seed.
user, _ = FromSeed(seed)
user, _ = nkeys.FromSeed(seed)

// Create a User who can only verify via a public key.
user, _ = FromPublicKey(publicKey)
// Create a User who can only verify signatures via a public key.
user, _ = nkeys.FromPublicKey(publicKey)

// Access the private key
// privateKey = "PAFXUA5H7BZERZSXYITNDSCBZE7ZZ..."
privateKey, _ = user.PrivateKey()
// Create a User KeyPair with our own random data.
var rawSeed [32]byte
_, err := io.ReadFull(rand.Reader, rawSeed[:]) // Or some other random source.
user2, _ := nkeys.FromRawSeed(PrefixByteUser, rawSeed)

```

Expand Down
10 changes: 7 additions & 3 deletions keypair.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package nkeys

import (
"bytes"
"crypto/rand"
"io"

"golang.org/x/crypto/ed25519"
Expand All @@ -26,12 +27,15 @@ type kp struct {
}

// createPair will create a KeyPair based on the rand entropy and a type/prefix byte. rand can be nil.
func createPair(rand io.Reader, prefix PrefixByte) (KeyPair, error) {
_, privateKey, err := ed25519.GenerateKey(rand)
func createPair(prefix PrefixByte) (KeyPair, error) {
var rawSeed [32]byte

_, err := io.ReadFull(rand.Reader, rawSeed[:])
if err != nil {
return nil, err
}
seed, err := EncodeSeed(prefix, privateKey)

seed, err := EncodeSeed(prefix, rawSeed[:])
if err != nil {
return nil, err
}
Expand Down
40 changes: 24 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package nkeys

import (
"errors"
"io"
)

// Errors
Expand All @@ -42,32 +41,32 @@ type KeyPair interface {
Verify(input []byte, sig []byte) error
}

// CreateUser will create an User typed KeyPair.
func CreateUser(rand io.Reader) (KeyPair, error) {
return createPair(rand, PrefixByteUser)
// CreateUser will create a User typed KeyPair.
func CreateUser() (KeyPair, error) {
return createPair(PrefixByteUser)
}

// CreateAccount will create an Account typed KeyPair.
func CreateAccount(rand io.Reader) (KeyPair, error) {
return createPair(rand, PrefixByteAccount)
func CreateAccount() (KeyPair, error) {
return createPair(PrefixByteAccount)
}

// CreateServer will create a server typed KeyPair.
func CreateServer(rand io.Reader) (KeyPair, error) {
return createPair(rand, PrefixByteServer)
// CreateServer will create a Server typed KeyPair.
func CreateServer() (KeyPair, error) {
return createPair(PrefixByteServer)
}

// CreateCluster will create a cluster typed KeyPair.
func CreateCluster(rand io.Reader) (KeyPair, error) {
return createPair(rand, PrefixByteCluster)
// CreateCluster will create a Cluster typed KeyPair.
func CreateCluster() (KeyPair, error) {
return createPair(PrefixByteCluster)
}

// CreateOperator will create an operator typed KeyPair.
func CreateOperator(rand io.Reader) (KeyPair, error) {
return createPair(rand, PrefixByteOperator)
// CreateOperator will create an Operator typed KeyPair.
func CreateOperator() (KeyPair, error) {
return createPair(PrefixByteOperator)
}

// FromPublicKey will create a KeyPair capable fo verifying signatures.
// FromPublicKey will create a KeyPair capable of verifying signatures.
func FromPublicKey(public string) (KeyPair, error) {
raw, err := decode(public)
if err != nil {
Expand All @@ -88,3 +87,12 @@ func FromSeed(seed string) (KeyPair, error) {
}
return &kp{seed}, nil
}

// Create a KeyPair from the raw 32 byte seed for a given type.
func FromRawSeed(prefix PrefixByte, rawSeed []byte) (KeyPair, error) {
seed, err := EncodeSeed(prefix, rawSeed)
if err != nil {
return nil, err
}
return &kp{seed}, nil
}
32 changes: 16 additions & 16 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestDecode(t *testing.T) {
}

func TestSeed(t *testing.T) {
var rawKeyShort [32]byte
var rawKeyShort [16]byte

_, err := io.ReadFull(rand.Reader, rawKeyShort[:])
if err != nil {
Expand All @@ -81,7 +81,7 @@ func TestSeed(t *testing.T) {
t.Fatalf("Did not receive ErrInvalidPrefixByte error, received %v", err)
}

var rawSeed [64]byte
var rawSeed [ed25519.SeedSize]byte

_, err = io.ReadFull(rand.Reader, rawSeed[:])
if err != nil {
Expand All @@ -107,7 +107,7 @@ func TestSeed(t *testing.T) {
}

func TestAccount(t *testing.T) {
account, err := CreateAccount(nil)
account, err := CreateAccount()
if err != nil {
t.Fatalf("Expected non-nil error on CreateAccount, received %v", err)
}
Expand Down Expand Up @@ -161,7 +161,7 @@ func TestAccount(t *testing.T) {
}

func TestUser(t *testing.T) {
user, err := CreateUser(nil)
user, err := CreateUser()
if err != nil {
t.Fatalf("Expected non-nil error on CreateUser, received %v", err)
}
Expand All @@ -183,7 +183,7 @@ func TestUser(t *testing.T) {
}

func TestOperator(t *testing.T) {
operator, err := CreateOperator(nil)
operator, err := CreateOperator()
if err != nil {
t.Fatalf("Expected non-nil error on CreateOperator, received %v", err)
}
Expand All @@ -205,7 +205,7 @@ func TestOperator(t *testing.T) {
}

func TestCluster(t *testing.T) {
cluster, err := CreateCluster(nil)
cluster, err := CreateCluster()
if err != nil {
t.Fatalf("Expected non-nil error on CreateCluster, received %v", err)
}
Expand All @@ -227,7 +227,7 @@ func TestCluster(t *testing.T) {
}

func TestServer(t *testing.T) {
server, err := CreateServer(nil)
server, err := CreateServer()
if err != nil {
t.Fatalf("Expected non-nil error on CreateServer, received %v", err)
}
Expand All @@ -250,7 +250,7 @@ func TestServer(t *testing.T) {

func TestFromPublic(t *testing.T) {
// Create a User
user, err := CreateUser(nil)
user, err := CreateUser()
if err != nil {
t.Fatalf("Expected non-nil error on CreateUser, received %v", err)
}
Expand Down Expand Up @@ -308,7 +308,7 @@ func TestFromPublic(t *testing.T) {
}

// Create another user to sign and make sure verify fails.
user2, _ := CreateUser(nil)
user2, _ := CreateUser()
sig, _ = user2.Sign(data)

err = pubUser.Verify(data, sig)
Expand All @@ -318,7 +318,7 @@ func TestFromPublic(t *testing.T) {
}

func TestFromSeed(t *testing.T) {
account, err := CreateAccount(nil)
account, err := CreateAccount()
if err != nil {
t.Fatalf("Expected non-nil error on CreateAccount, received %v", err)
}
Expand Down Expand Up @@ -356,11 +356,11 @@ func TestFromSeed(t *testing.T) {

func TestKeyPairFailures(t *testing.T) {
var tooshort [8]byte
if _, err := createPair(bytes.NewReader(tooshort[:]), PrefixByteUser); err == nil {
if _, err := EncodeSeed(PrefixByteUser, tooshort[:]); err == nil {
t.Fatal("Expected an error with insufficient rand")
}

if _, err := createPair(nil, PrefixBytePrivate); err == nil {
if _, err := createPair(PrefixBytePrivate); err == nil {
t.Fatal("Expected an error with non-public prefix")
}
kpbad := &kp{"SEEDBAD"}
Expand All @@ -387,7 +387,7 @@ func TestBadDecode(t *testing.T) {
}

// Create invalid checksum
account, _ := CreateAccount(nil)
account, _ := CreateAccount()
pkey, _ := account.PublicKey()
bpkey := []byte(pkey)
bpkey[len(pkey)-1] = '0'
Expand Down Expand Up @@ -442,7 +442,7 @@ func BenchmarkSign(b *testing.B) {
rand.Read(data)
base64.RawURLEncoding.Encode(nonce, data)

user, err := CreateUser(nil)
user, err := CreateUser()
if err != nil {
b.Fatalf("Error creating User Nkey: %v", err)
}
Expand All @@ -461,7 +461,7 @@ func BenchmarkVerify(b *testing.B) {
rand.Read(data)
base64.RawURLEncoding.Encode(nonce, data)

user, err := CreateUser(nil)
user, err := CreateUser()
if err != nil {
b.Fatalf("Error creating User Nkey: %v", err)
}
Expand All @@ -484,7 +484,7 @@ func BenchmarkPublicVerify(b *testing.B) {
rand.Read(data)
base64.RawURLEncoding.Encode(nonce, data)

user, err := CreateUser(nil)
user, err := CreateUser()
if err != nil {
b.Fatalf("Error creating User Nkey: %v", err)
}
Expand Down
10 changes: 5 additions & 5 deletions nk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ Create a user keypair. The result will be an encoded seed. Seeds are prefixed wi
```bash
> nk -gen user > user.seed
> cat user.seed
SUAHLNHIFX6MQ2TW5LCELSEWQK6NLV4T4QKP45OLEQUVWWQVM5PNXBTGCWKMHDH3L7UY5Y7PFYGBZCSIO2U6QY5QSVEI27B3HY5Q7MNVLHVA2
SUAKYRHVIOREXV7EUZTBHUHL7NUMHPMAS7QMDU3GTIUWEI5LDNOXD43IZY
```

You can obtain the public key for an nkey seed as follows.

```bash
> nk -inkey user.seed -pubout > user.pub
> cat user.pub
UBTBLFGDRT5V72MO4PXS4DA4RJEHNKPIMOYJKSENPQ5T4OYPWG2VSMZT
UD466L6EBCM3YY5HEGHJANNTN4LSKTSUXTH7RILHCKEQMQHTBNLHJJXT
```

Signing the contents of a file
Expand All @@ -52,17 +52,17 @@ Hello World!

> nk -sign some.txt -inkey user.seed > some.sig
> cat some.sig
ZtD-kBrNlB8zjGY8lpvBhyW08OTP3uzM1qk7DfJSbKhbZ4iBJN52o-_NNc_Kdi7iQhfoR6nWWKrEWB2_ygnfBA
0CK1XmkxNfUGfudxliWTWeoETgIo23m9qowS9yTfYFSrjR8HgAW63jQ3NxPU_jG38hZPW61IZSun37N690CkDg
```

Verifying a signature. You can use the seed or the public key.

```bash
> nk -verify some.txt -sigfile some.sig -inkey user.seed
verification succeeded
Verified OK

> nk -verify some.txt -sigfile some.sig -pubin user.pub
verification succeeded
Verified OK
```

## License
Expand Down
44 changes: 26 additions & 18 deletions nk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package main

import (
"crypto/rand"
"encoding/base64"
"flag"
"io"
Expand All @@ -26,7 +27,7 @@ import (
)

func usage() {
log.Fatalf("Usage: nk [-gen type] [-sign file] [-verify file] [-inkey keyfile] [-pubin keyfile] [-pubout] [-e entropy]\n")
log.Fatalf("Usage: nk [-gen type] [-sign file] [-verify file] [-inkey keyfile] [-pubin keyfile] [-sigfile file] [-pubout] [-e entropy]\n")
}

func main() {
Expand Down Expand Up @@ -164,16 +165,30 @@ func verify(fname, keyFile, pubFile, sigFile string) {
if err := kp.Verify(content, sig); err != nil {
log.Fatal(err)
}
log.Printf("verification succeeded")
log.Printf("Verified OK")
}

func createKey(keyType, entropy string) {
keyType = strings.ToLower(keyType)
var kp nkeys.KeyPair
var err error
var pre nkeys.PrefixByte

var ef io.Reader
switch keyType {
case "user":
pre = nkeys.PrefixByteUser
case "account":
pre = nkeys.PrefixByteAccount
case "server":
pre = nkeys.PrefixByteServer
case "cluster":
pre = nkeys.PrefixByteCluster
case "operator":
pre = nkeys.PrefixByteOperator
default:
log.Fatalf("Usage: nk -gen [user|account|server|cluster|operator]\n")
}

// See if we override entropy.
ef := rand.Reader
if entropy != "" {
r, err := os.Open(entropy)
if err != nil {
Expand All @@ -182,20 +197,13 @@ func createKey(keyType, entropy string) {
ef = r
}

switch keyType {
case "user":
kp, err = nkeys.CreateUser(ef)
case "account":
kp, err = nkeys.CreateAccount(ef)
case "server":
kp, err = nkeys.CreateServer(ef)
case "cluster":
kp, err = nkeys.CreateCluster(ef)
case "operator":
kp, err = nkeys.CreateOperator(ef)
default:
log.Fatalf("Usage: nk -gen [user|account|server|cluster|operator]\n")
// Create raw seed from source or random.
var rawSeed [32]byte
_, err := io.ReadFull(ef, rawSeed[:]) // Or some other random source.
if err != nil {
log.Fatalf("Error reading from %s: %v", ef, err)
}
kp, err := nkeys.FromRawSeed(pre, rawSeed[:])
if err != nil {
log.Fatalf("Error creating %s: %v", keyType, err)
}
Expand Down

0 comments on commit 56d584c

Please sign in to comment.