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  }