github.com/decred/politeia@v1.4.0/politeiad/api/v1/identity/identity.go (about)

     1  // Copyright (c) 2016-2017 Company 0, LLC.
     2  // Copyright (c) 2017-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  // zkidentity package manages public and private identities.
     7  package identity
     8  
     9  import (
    10  	"crypto/rand"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  	"os"
    17  
    18  	"golang.org/x/crypto/ed25519"
    19  )
    20  
    21  var (
    22  	prng = rand.Reader
    23  
    24  	ErrNotEqual         = errors.New("not equal")
    25  	ErrInvalidSignature = errors.New("invalid signature")
    26  )
    27  
    28  const (
    29  	PrivateKeySize = ed25519.PrivateKeySize
    30  	SignatureSize  = ed25519.SignatureSize
    31  	PublicKeySize  = ed25519.PublicKeySize
    32  )
    33  
    34  type FullIdentity struct {
    35  	Public     PublicIdentity       // public key
    36  	PrivateKey [PrivateKeySize]byte // private key, exported for marshaling
    37  }
    38  
    39  func (fi *FullIdentity) Marshal() ([]byte, error) {
    40  	b, err := json.Marshal(fi)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	return b, nil
    46  }
    47  
    48  func UnmarshalFullIdentity(data []byte) (*FullIdentity, error) {
    49  	fi := FullIdentity{}
    50  	err := json.Unmarshal(data, &fi)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	return &fi, nil
    56  }
    57  
    58  type PublicIdentity struct {
    59  	Key [PublicKeySize]byte // public key
    60  }
    61  
    62  func New() (*FullIdentity, error) {
    63  	fi := FullIdentity{}
    64  	pub, priv, err := ed25519.GenerateKey(prng)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	// move keys in place
    70  	copy(fi.Public.Key[:], pub[:])
    71  	copy(fi.PrivateKey[:], priv[:])
    72  	zero(pub[:])
    73  	zero(priv[:])
    74  
    75  	return &fi, nil
    76  }
    77  
    78  func LoadFullIdentity(filename string) (*FullIdentity, error) {
    79  	idx, err := os.ReadFile(filename)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	id, err := UnmarshalFullIdentity(idx)
    84  	if err != nil {
    85  		return nil, fmt.Errorf("could not unmarshal identity")
    86  	}
    87  
    88  	return id, nil
    89  }
    90  
    91  func (fi *FullIdentity) Save(filename string) error {
    92  	id, err := fi.Marshal()
    93  	if err != nil {
    94  		return fmt.Errorf("could not marshal identity")
    95  	}
    96  	return os.WriteFile(filename, id, 0600)
    97  }
    98  
    99  func (fi *FullIdentity) SignMessage(message []byte) [SignatureSize]byte {
   100  	var signature [SignatureSize]byte
   101  	copy(signature[:], ed25519.Sign(fi.PrivateKey[:], message))
   102  
   103  	return signature
   104  }
   105  
   106  func UnmarshalPublicIdentity(data []byte) (*PublicIdentity, error) {
   107  	pi := PublicIdentity{}
   108  	err := json.Unmarshal(data, &pi)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	return &pi, nil
   114  }
   115  
   116  func PublicIdentityFromBytes(data []byte) (*PublicIdentity, error) {
   117  	pi := PublicIdentity{}
   118  	if len(data) != PublicKeySize {
   119  		return nil, fmt.Errorf("invalid public key length")
   120  	}
   121  	copy(pi.Key[:], data)
   122  	return &pi, nil
   123  }
   124  
   125  // PublicIdentityFromString converts a hex encoded public key into a
   126  // PublicIdentity.
   127  func PublicIdentityFromString(id string) (*PublicIdentity, error) {
   128  	pk, err := hex.DecodeString(id)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	return PublicIdentityFromBytes(pk)
   133  }
   134  
   135  func LoadPublicIdentity(filename string) (*PublicIdentity, error) {
   136  	idx, err := os.ReadFile(filename)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	id, err := UnmarshalPublicIdentity(idx)
   141  	if err != nil {
   142  		return nil, fmt.Errorf("could not unmarshal public identity")
   143  	}
   144  
   145  	return id, nil
   146  }
   147  
   148  func (p PublicIdentity) VerifyMessage(msg []byte, sig [SignatureSize]byte) bool {
   149  	return ed25519.Verify(p.Key[:], msg, sig[:])
   150  }
   151  
   152  func (p PublicIdentity) String() string {
   153  	return hex.EncodeToString(p.Key[:])
   154  }
   155  
   156  func (p PublicIdentity) Fingerprint() string {
   157  	return base64.StdEncoding.EncodeToString(p.Key[:])
   158  }
   159  
   160  func (p *PublicIdentity) Marshal() ([]byte, error) {
   161  	b, err := json.Marshal(p)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	return b, nil
   167  }
   168  
   169  func (pi *PublicIdentity) SavePublicIdentity(filename string) error {
   170  	id, err := pi.Marshal()
   171  	if err != nil {
   172  		return fmt.Errorf("could not marshal public identity")
   173  	}
   174  	return os.WriteFile(filename, id, 0600)
   175  }
   176  
   177  // Zero out a byte slice.
   178  func zero(in []byte) {
   179  	if in == nil {
   180  		return
   181  	}
   182  	for i := 0; i < len(in); i++ {
   183  		in[i] ^= in[i]
   184  	}
   185  }
   186  
   187  func SignatureFromString(signature string) (*[SignatureSize]byte, error) {
   188  	s, err := hex.DecodeString(signature)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	if len(s) != SignatureSize {
   193  		return nil, ErrInvalidSignature
   194  	}
   195  
   196  	var sig [SignatureSize]byte
   197  	copy(sig[:], s)
   198  	return &sig, nil
   199  }