github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/crypto/ecies/ecies.go (about) 1 // Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is> 2 // Copyright (c) 2012 The Go Authors. All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 package ecies 31 32 import ( 33 "crypto/cipher" 34 "crypto/ecdsa" 35 "crypto/elliptic" 36 "crypto/hmac" 37 "crypto/subtle" 38 "encoding/binary" 39 "errors" 40 "hash" 41 "io" 42 "math/big" 43 44 "github.com/ethereum/go-ethereum/crypto" 45 ) 46 47 var ( 48 ErrImport = errors.New("ecies: failed to import key") 49 ErrInvalidCurve = errors.New("ecies: invalid elliptic curve") 50 ErrInvalidPublicKey = errors.New("ecies: invalid public key") 51 ErrSharedKeyIsPointAtInfinity = errors.New("ecies: shared key is point at infinity") 52 ErrSharedKeyTooBig = errors.New("ecies: shared key params are too big") 53 ) 54 55 // PublicKey is a representation of an elliptic curve public key. 56 type PublicKey struct { 57 X *big.Int 58 Y *big.Int 59 elliptic.Curve 60 Params *ECIESParams 61 } 62 63 // Export an ECIES public key as an ECDSA public key. 64 func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { 65 return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} 66 } 67 68 // Import an ECDSA public key as an ECIES public key. 69 func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { 70 return &PublicKey{ 71 X: pub.X, 72 Y: pub.Y, 73 Curve: pub.Curve, 74 Params: ParamsFromCurve(pub.Curve), 75 } 76 } 77 78 // PrivateKey is a representation of an elliptic curve private key. 79 type PrivateKey struct { 80 PublicKey 81 D *big.Int 82 } 83 84 // Export an ECIES private key as an ECDSA private key. 85 func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { 86 pub := &prv.PublicKey 87 pubECDSA := pub.ExportECDSA() 88 return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} 89 } 90 91 // Import an ECDSA private key as an ECIES private key. 92 func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { 93 pub := ImportECDSAPublic(&prv.PublicKey) 94 return &PrivateKey{*pub, prv.D} 95 } 96 97 // Generate an elliptic curve public / private keypair. If params is nil, 98 // the recommended default parameters for the key will be chosen. 99 func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { 100 sk, err := ecdsa.GenerateKey(curve, rand) 101 if err != nil { 102 return 103 } 104 prv = new(PrivateKey) 105 prv.PublicKey.X = sk.X 106 prv.PublicKey.Y = sk.Y 107 prv.PublicKey.Curve = curve 108 prv.D = new(big.Int).Set(sk.D) 109 if params == nil { 110 params = ParamsFromCurve(curve) 111 } 112 prv.PublicKey.Params = params 113 return 114 } 115 116 // MaxSharedKeyLength returns the maximum length of the shared key the 117 // public key can produce. 118 func MaxSharedKeyLength(pub *PublicKey) int { 119 return (pub.Curve.Params().BitSize + 7) / 8 120 } 121 122 // ECDH key agreement method used to establish secret keys for encryption. 123 func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { 124 if prv.PublicKey.Curve != pub.Curve { 125 return nil, ErrInvalidCurve 126 } 127 if skLen+macLen > MaxSharedKeyLength(pub) { 128 return nil, ErrSharedKeyTooBig 129 } 130 131 x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) 132 if x == nil { 133 return nil, ErrSharedKeyIsPointAtInfinity 134 } 135 136 sk = make([]byte, skLen+macLen) 137 skBytes := x.Bytes() 138 copy(sk[len(sk)-len(skBytes):], skBytes) 139 return sk, nil 140 } 141 142 var ( 143 ErrSharedTooLong = errors.New("ecies: shared secret is too long") 144 ErrInvalidMessage = errors.New("ecies: invalid message") 145 ) 146 147 // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). 148 func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte { 149 counterBytes := make([]byte, 4) 150 k := make([]byte, 0, roundup(kdLen, hash.Size())) 151 for counter := uint32(1); len(k) < kdLen; counter++ { 152 binary.BigEndian.PutUint32(counterBytes, counter) 153 hash.Reset() 154 hash.Write(counterBytes) 155 hash.Write(z) 156 hash.Write(s1) 157 k = hash.Sum(k) 158 } 159 return k[:kdLen] 160 } 161 162 // roundup rounds size up to the next multiple of blocksize. 163 func roundup(size, blocksize int) int { 164 return size + blocksize - (size % blocksize) 165 } 166 167 // deriveKeys creates the encryption and MAC keys using concatKDF. 168 func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) { 169 K := concatKDF(hash, z, s1, 2*keyLen) 170 Ke = K[:keyLen] 171 Km = K[keyLen:] 172 hash.Reset() 173 hash.Write(Km) 174 Km = hash.Sum(Km[:0]) 175 return Ke, Km 176 } 177 178 // messageTag computes the MAC of a message (called the tag) as per 179 // SEC 1, 3.5. 180 func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte { 181 mac := hmac.New(hash, km) 182 mac.Write(msg) 183 mac.Write(shared) 184 tag := mac.Sum(nil) 185 return tag 186 } 187 188 // Generate an initialisation vector for CTR mode. 189 func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) { 190 iv = make([]byte, params.BlockSize) 191 _, err = io.ReadFull(rand, iv) 192 return 193 } 194 195 // symEncrypt carries out CTR encryption using the block cipher specified in the 196 func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) { 197 c, err := params.Cipher(key) 198 if err != nil { 199 return 200 } 201 202 iv, err := generateIV(params, rand) 203 if err != nil { 204 return 205 } 206 ctr := cipher.NewCTR(c, iv) 207 208 ct = make([]byte, len(m)+params.BlockSize) 209 copy(ct, iv) 210 ctr.XORKeyStream(ct[params.BlockSize:], m) 211 return 212 } 213 214 // symDecrypt carries out CTR decryption using the block cipher specified in 215 // the parameters 216 func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { 217 c, err := params.Cipher(key) 218 if err != nil { 219 return 220 } 221 222 ctr := cipher.NewCTR(c, ct[:params.BlockSize]) 223 224 m = make([]byte, len(ct)-params.BlockSize) 225 ctr.XORKeyStream(m, ct[params.BlockSize:]) 226 return 227 } 228 229 // Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. 230 // 231 // s1 and s2 contain shared information that is not part of the resulting 232 // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the 233 // shared information parameters aren't being used, they should be nil. 234 func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { 235 params, err := pubkeyParams(pub) 236 if err != nil { 237 return nil, err 238 } 239 240 R, err := GenerateKey(rand, pub.Curve, params) 241 if err != nil { 242 return nil, err 243 } 244 245 z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen) 246 if err != nil { 247 return nil, err 248 } 249 250 hash := params.Hash() 251 Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) 252 253 em, err := symEncrypt(rand, params, Ke, m) 254 if err != nil || len(em) <= params.BlockSize { 255 return nil, err 256 } 257 258 d := messageTag(params.Hash, Km, em, s2) 259 260 if curve, ok := pub.Curve.(crypto.EllipticCurve); ok { 261 Rb := curve.Marshal(R.PublicKey.X, R.PublicKey.Y) 262 ct = make([]byte, len(Rb)+len(em)+len(d)) 263 copy(ct, Rb) 264 copy(ct[len(Rb):], em) 265 copy(ct[len(Rb)+len(em):], d) 266 return ct, nil 267 } 268 return nil, ErrInvalidCurve 269 } 270 271 // Decrypt decrypts an ECIES ciphertext. 272 func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { 273 if len(c) == 0 { 274 return nil, ErrInvalidMessage 275 } 276 params, err := pubkeyParams(&prv.PublicKey) 277 if err != nil { 278 return nil, err 279 } 280 281 hash := params.Hash() 282 283 var ( 284 rLen int 285 hLen int = hash.Size() 286 mStart int 287 mEnd int 288 ) 289 290 switch c[0] { 291 case 2, 3, 4: 292 rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 293 if len(c) < (rLen + hLen + 1) { 294 return nil, ErrInvalidMessage 295 } 296 default: 297 return nil, ErrInvalidPublicKey 298 } 299 300 mStart = rLen 301 mEnd = len(c) - hLen 302 303 R := new(PublicKey) 304 R.Curve = prv.PublicKey.Curve 305 306 if curve, ok := R.Curve.(crypto.EllipticCurve); ok { 307 R.X, R.Y = curve.Unmarshal(c[:rLen]) 308 if R.X == nil { 309 return nil, ErrInvalidPublicKey 310 } 311 312 z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) 313 if err != nil { 314 return nil, err 315 } 316 Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) 317 318 d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) 319 if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { 320 return nil, ErrInvalidMessage 321 } 322 return symDecrypt(params, Ke, c[mStart:mEnd]) 323 } 324 return nil, ErrInvalidCurve 325 }