github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/ecies/ecies.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package ecies 19 20 import ( 21 "crypto/cipher" 22 "crypto/ecdsa" 23 "crypto/elliptic" 24 "crypto/hmac" 25 "crypto/subtle" 26 "fmt" 27 "hash" 28 "io" 29 "math/big" 30 ) 31 32 var ( 33 ErrImport = fmt.Errorf("ecies: failed to import key") 34 ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve") 35 ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters") 36 ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key") 37 ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity") 38 ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big") 39 ) 40 41 // PublicKey is a representation of an elliptic curve public key. 42 type PublicKey struct { 43 X *big.Int 44 Y *big.Int 45 elliptic.Curve 46 Params *ECIESParams 47 } 48 49 // Export an ECIES public key as an ECDSA public key. 50 func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { 51 return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} 52 } 53 54 // Import an ECDSA public key as an ECIES public key. 55 func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { 56 return &PublicKey{ 57 X: pub.X, 58 Y: pub.Y, 59 Curve: pub.Curve, 60 Params: ParamsFromCurve(pub.Curve), 61 } 62 } 63 64 // PrivateKey is a representation of an elliptic curve private key. 65 type PrivateKey struct { 66 PublicKey 67 D *big.Int 68 } 69 70 // Export an ECIES private key as an ECDSA private key. 71 func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { 72 pub := &prv.PublicKey 73 pubECDSA := pub.ExportECDSA() 74 return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} 75 } 76 77 // Import an ECDSA private key as an ECIES private key. 78 func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { 79 pub := ImportECDSAPublic(&prv.PublicKey) 80 return &PrivateKey{*pub, prv.D} 81 } 82 83 // Generate an elliptic curve public / private keypair. If params is nil, 84 // the recommended default parameters for the key will be chosen. 85 func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { 86 pb, x, y, err := elliptic.GenerateKey(curve, rand) 87 if err != nil { 88 return 89 } 90 prv = new(PrivateKey) 91 prv.PublicKey.X = x 92 prv.PublicKey.Y = y 93 prv.PublicKey.Curve = curve 94 prv.D = new(big.Int).SetBytes(pb) 95 if params == nil { 96 params = ParamsFromCurve(curve) 97 } 98 prv.PublicKey.Params = params 99 return 100 } 101 102 // MaxSharedKeyLength returns the maximum length of the shared key the 103 // public key can produce. 104 func MaxSharedKeyLength(pub *PublicKey) int { 105 return (pub.Curve.Params().BitSize + 7) / 8 106 } 107 108 // ECDH key agreement method used to establish secret keys for encryption. 109 func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { 110 if prv.PublicKey.Curve != pub.Curve { 111 return nil, ErrInvalidCurve 112 } 113 if skLen+macLen > MaxSharedKeyLength(pub) { 114 return nil, ErrSharedKeyTooBig 115 } 116 117 x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) 118 if x == nil { 119 return nil, ErrSharedKeyIsPointAtInfinity 120 } 121 122 sk = make([]byte, skLen+macLen) 123 skBytes := x.Bytes() 124 copy(sk[len(sk)-len(skBytes):], skBytes) 125 return sk, nil 126 } 127 128 var ( 129 ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data") 130 ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long") 131 ErrInvalidMessage = fmt.Errorf("ecies: invalid message") 132 ) 133 134 var ( 135 big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil) 136 big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1)) 137 ) 138 139 func incCounter(ctr []byte) { 140 if ctr[3]++; ctr[3] != 0 { 141 return 142 } 143 if ctr[2]++; ctr[2] != 0 { 144 return 145 } 146 if ctr[1]++; ctr[1] != 0 { 147 return 148 } 149 if ctr[0]++; ctr[0] != 0 { 150 return 151 } 152 } 153 154 // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). 155 func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) { 156 if s1 == nil { 157 s1 = make([]byte, 0) 158 } 159 160 reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8) 161 if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 { 162 fmt.Println(big2To32M1) 163 return nil, ErrKeyDataTooLong 164 } 165 166 counter := []byte{0, 0, 0, 1} 167 k = make([]byte, 0) 168 169 for i := 0; i <= reps; i++ { 170 hash.Write(counter) 171 hash.Write(z) 172 hash.Write(s1) 173 k = append(k, hash.Sum(nil)...) 174 hash.Reset() 175 incCounter(counter) 176 } 177 178 k = k[:kdLen] 179 return 180 } 181 182 // messageTag computes the MAC of a message (called the tag) as per 183 // SEC 1, 3.5. 184 func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte { 185 mac := hmac.New(hash, km) 186 mac.Write(msg) 187 mac.Write(shared) 188 tag := mac.Sum(nil) 189 return tag 190 } 191 192 // Generate an initialisation vector for CTR mode. 193 func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) { 194 iv = make([]byte, params.BlockSize) 195 _, err = io.ReadFull(rand, iv) 196 return 197 } 198 199 // symEncrypt carries out CTR encryption using the block cipher specified in the 200 // parameters. 201 func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) { 202 c, err := params.Cipher(key) 203 if err != nil { 204 return 205 } 206 207 iv, err := generateIV(params, rand) 208 if err != nil { 209 return 210 } 211 ctr := cipher.NewCTR(c, iv) 212 213 ct = make([]byte, len(m)+params.BlockSize) 214 copy(ct, iv) 215 ctr.XORKeyStream(ct[params.BlockSize:], m) 216 return 217 } 218 219 // symDecrypt carries out CTR decryption using the block cipher specified in 220 // the parameters 221 func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { 222 c, err := params.Cipher(key) 223 if err != nil { 224 return 225 } 226 227 ctr := cipher.NewCTR(c, ct[:params.BlockSize]) 228 229 m = make([]byte, len(ct)-params.BlockSize) 230 ctr.XORKeyStream(m, ct[params.BlockSize:]) 231 return 232 } 233 234 // Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. 235 // 236 // s1 and s2 contain shared information that is not part of the resulting 237 // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the 238 // shared information parameters aren't being used, they should be nil. 239 func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { 240 params := pub.Params 241 if params == nil { 242 if params = ParamsFromCurve(pub.Curve); params == nil { 243 err = ErrUnsupportedECIESParameters 244 return 245 } 246 } 247 R, err := GenerateKey(rand, pub.Curve, params) 248 if err != nil { 249 return 250 } 251 252 hash := params.Hash() 253 z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen) 254 if err != nil { 255 return 256 } 257 K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) 258 if err != nil { 259 return 260 } 261 Ke := K[:params.KeyLen] 262 Km := K[params.KeyLen:] 263 hash.Write(Km) 264 Km = hash.Sum(nil) 265 hash.Reset() 266 267 em, err := symEncrypt(rand, params, Ke, m) 268 if err != nil || len(em) <= params.BlockSize { 269 return 270 } 271 272 d := messageTag(params.Hash, Km, em, s2) 273 274 Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) 275 ct = make([]byte, len(Rb)+len(em)+len(d)) 276 copy(ct, Rb) 277 copy(ct[len(Rb):], em) 278 copy(ct[len(Rb)+len(em):], d) 279 return 280 } 281 282 // Decrypt decrypts an ECIES ciphertext. 283 func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { 284 if len(c) == 0 { 285 return nil, ErrInvalidMessage 286 } 287 params := prv.PublicKey.Params 288 if params == nil { 289 if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil { 290 err = ErrUnsupportedECIESParameters 291 return 292 } 293 } 294 hash := params.Hash() 295 296 var ( 297 rLen int 298 hLen int = hash.Size() 299 mStart int 300 mEnd int 301 ) 302 303 switch c[0] { 304 case 2, 3, 4: 305 rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 306 if len(c) < (rLen + hLen + 1) { 307 err = ErrInvalidMessage 308 return 309 } 310 default: 311 err = ErrInvalidPublicKey 312 return 313 } 314 315 mStart = rLen 316 mEnd = len(c) - hLen 317 318 R := new(PublicKey) 319 R.Curve = prv.PublicKey.Curve 320 R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) 321 if R.X == nil { 322 err = ErrInvalidPublicKey 323 return 324 } 325 if !R.Curve.IsOnCurve(R.X, R.Y) { 326 err = ErrInvalidCurve 327 return 328 } 329 330 z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) 331 if err != nil { 332 return 333 } 334 335 K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) 336 if err != nil { 337 return 338 } 339 340 Ke := K[:params.KeyLen] 341 Km := K[params.KeyLen:] 342 hash.Write(Km) 343 Km = hash.Sum(nil) 344 hash.Reset() 345 346 d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) 347 if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { 348 err = ErrInvalidMessage 349 return 350 } 351 352 m, err = symDecrypt(params, Ke, c[mStart:mEnd]) 353 return 354 }