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