Skip to content

Commit

Permalink
update account package and encrypted private key
Browse files Browse the repository at this point in the history
  • Loading branch information
Thykof committed Oct 12, 2023
1 parent 7c05263 commit 37b129f
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 19 deletions.
19 changes: 10 additions & 9 deletions pkg/types/encrypted_private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"crypto/ed25519"
"fmt"

"github.com/awnumar/memguard"
"github.com/btcsuite/btcutil/base58"
Expand Down Expand Up @@ -83,9 +84,9 @@ func (a *EncryptedPrivateKey) UnmarshalBinary(data []byte) error {
func (e *EncryptedPrivateKey) Sign(guardedPassword *memguard.LockedBuffer, salt, nonce, data []byte) ([]byte, error) {
digest := blake3.Sum256(data)

privateKeyInClear, err := PrivateKey(guardedPassword, salt, nonce, e.Data)
privateKeyInClear, err := privateKey(guardedPassword, salt, nonce, e.Data)
if err != nil {
return nil, err
return nil, fmt.Errorf("Sign: %w", err)
}

defer privateKeyInClear.Destroy()
Expand All @@ -95,9 +96,9 @@ func (e *EncryptedPrivateKey) Sign(guardedPassword *memguard.LockedBuffer, salt,

// PublicKey returns the public key corresponding to the private key. Guarded password is destroyed.
func (e *EncryptedPrivateKey) PublicKey(guardedPassword *memguard.LockedBuffer, salt, nonce []byte) (*PublicKey, error) {
privateKeyInClear, err := PrivateKey(guardedPassword, salt, nonce, e.Data)
privateKeyInClear, err := privateKey(guardedPassword, salt, nonce, e.Data)
if err != nil {
return nil, err
return nil, fmt.Errorf("PublicKey: %w", err)
}

publicKeyBytes := ed25519.PrivateKey(privateKeyInClear.Bytes()).Public().(ed25519.PublicKey)
Expand All @@ -115,9 +116,9 @@ func (e *EncryptedPrivateKey) PublicKey(guardedPassword *memguard.LockedBuffer,

// PrivateKeyTextInClear returns the private key in clear. Guarded password is destroyed.
func (e *EncryptedPrivateKey) PrivateKeyTextInClear(guardedPassword *memguard.LockedBuffer, salt, nonce, encryptedKey []byte) (*memguard.LockedBuffer, error) {
privateKeyInClear, err := PrivateKey(guardedPassword, salt, nonce, encryptedKey)
privateKeyInClear, err := privateKey(guardedPassword, salt, nonce, encryptedKey)
if err != nil {
return nil, err
return nil, fmt.Errorf("PrivateKeyTextInClear: %w", err)
}

seed := ed25519.PrivateKey(privateKeyInClear.Bytes()).Seed()
Expand All @@ -133,7 +134,7 @@ func (e *EncryptedPrivateKey) PrivateKeyTextInClear(guardedPassword *memguard.Lo

// PasswordIsValid returns true if the password is valid for the account. It destroys the guarded password.
func (e *EncryptedPrivateKey) PasswordIsValid(guardedPassword *memguard.LockedBuffer, salt, nonce, encryptedKey []byte) bool {
privateKeyInClear, err := PrivateKey(guardedPassword, salt, nonce, e.Data)
privateKeyInClear, err := privateKey(guardedPassword, salt, nonce, e.Data)
if err != nil {
return false
}
Expand All @@ -142,9 +143,9 @@ func (e *EncryptedPrivateKey) PasswordIsValid(guardedPassword *memguard.LockedBu
return err == nil
}

// PrivateKey returns the private key in clear.
// privateKey returns the private key in clear.
// Guarded password is destroyed.
func PrivateKey(guardedPassword *memguard.LockedBuffer, salt, nonce, encryptedKey []byte) (*memguard.LockedBuffer, error) {
func privateKey(guardedPassword *memguard.LockedBuffer, salt, nonce, encryptedKey []byte) (*memguard.LockedBuffer, error) {
aeadCipher, secretKey, err := crypto.NewSecretCipher(guardedPassword.Bytes(), salt[:])
defer guardedPassword.Destroy()
defer secretKey.Destroy()
Expand Down
16 changes: 7 additions & 9 deletions pkg/wallet/account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package account
import (
"crypto/ed25519"
"crypto/rand"
"errors"
"fmt"

"github.com/awnumar/memguard"
Expand All @@ -17,6 +18,8 @@ const (
AccountLastVersion = 1
)

var ErrInvalidPrivateKey = errors.New("invalid private key")

type Account struct {
Version *uint8 `yaml:"Version"`
Nickname string `yaml:"Nickname,omitempty"`
Expand All @@ -38,7 +41,7 @@ func New(version *uint8, nickname string, address types.Address, salt [16]byte,
}

if !NicknameIsValid(nickname) {
return nil, fmt.Errorf("invalid nickname: %s", nickname)
return nil, fmt.Errorf("%w: %s", ErrInvalidNickname, nickname)
}

if err := address.Validate(address.Version, object.UserAddress, object.SmartContractAddress); err != nil {
Expand Down Expand Up @@ -123,8 +126,7 @@ func NewGenerated(guardedPassword *memguard.LockedBuffer, nickname string) (*Acc
return nil, fmt.Errorf("creating secret cipher: %w", err)
}

// secretBuffer is the secret key in clear without the version.
secretBuffer := memguard.NewBufferFromBytes(privateKeyBytes.Seed())
secretBuffer := memguard.NewBufferFromBytes(privateKeyBytes)
encryptedSecret := crypto.SealSecret(aeadCipher, nonce[:], secretBuffer)
secretKey.Destroy()

Expand Down Expand Up @@ -174,7 +176,7 @@ func NewFromPrivateKey(guardedPassword *memguard.LockedBuffer, nickname string,
seedBuffer := memguard.NewBufferFromBytes(seed)
if err != nil {
seedBuffer.Destroy()
return nil, fmt.Errorf("decoding base58 private key: %w", err)
return nil, fmt.Errorf("%w: decoding base58 private key: %w", ErrInvalidPrivateKey, err)
}

privateKey := memguard.NewBufferFromBytes(ed25519.NewKeyFromSeed(seedBuffer.Bytes()))
Expand Down Expand Up @@ -234,7 +236,7 @@ func (a *Account) PasswordIsValid(guardedPassword *memguard.LockedBuffer) bool {
func (a *Account) Unmarshal(data []byte) error {
err := yaml.Unmarshal(data, &a)
if err != nil {
return fmt.Errorf("unmarshalling account: %w", err)
return err
}

if len(a.Salt) == 0 || a.Salt == [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} {
Expand All @@ -257,9 +259,5 @@ func (a *Account) Unmarshal(data []byte) error {
// return fmt.Errorf("missing version")
// }

if !NicknameIsValid(a.Nickname) {
return fmt.Errorf("invalid nickname: %s", a.Nickname) // TODO: add unit test
}

return nil
}
15 changes: 15 additions & 0 deletions pkg/wallet/account/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,21 @@ func TestSign(t *testing.T) {
assert.Equal(t, byte(types.EncryptedPrivateKeyLastVersion), signature[0])
expectedSignature := []byte{0x0, 0xe7, 0xeb, 0xd0, 0x39, 0xd3, 0xa3, 0x70, 0x70, 0xee, 0x38, 0xee, 0x95, 0x78, 0xd7, 0x3d, 0x7d, 0x74, 0xc4, 0x1a, 0x3, 0x1c, 0xfa, 0x3, 0xd4, 0x34, 0x1d, 0x67, 0x81, 0x64, 0x2c, 0xb7, 0xb0, 0x7c, 0xab, 0x30, 0xf1, 0x1d, 0x22, 0x39, 0x27, 0x7c, 0x9d, 0x5b, 0x4c, 0x9e, 0xcb, 0xa4, 0xe9, 0x8a, 0x5, 0x42, 0x20, 0xbb, 0x97, 0x7, 0x5e, 0x71, 0x87, 0x10, 0x40, 0xec, 0x8e, 0x62, 0x7}
assert.Equal(t, expectedSignature, signature)

t.Run("sign with new generated account", func(t *testing.T) {
// Create test values for the password and nickname
samplePassword := memguard.NewBufferFromBytes([]byte(password))

// Call the New function with the test values
account, err := NewGenerated(samplePassword, nickname)
assert.NoError(t, err)

samplePassword = memguard.NewBufferFromBytes([]byte(password))

signature, err := account.Sign(samplePassword, sampleData)
assert.NoError(t, err)
assert.Len(t, signature, 64+1) // +1 for the prefix
})
}

func TestMarshal(t *testing.T) {
Expand Down
7 changes: 6 additions & 1 deletion pkg/wallet/account/validation.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package account

import "regexp"
import (
"errors"
"regexp"
)

const (
MaxNicknameLength = 32
)

var ErrInvalidNickname = errors.New("nickname invalid")

// NicknameIsValid validates the nickname using the following rules:
// - must have at least 1 character
// - must contain only alphanumeric characters, underscores and dashes
Expand Down

0 comments on commit 37b129f

Please sign in to comment.