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  }