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