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 }