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