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