github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/ecies/ecies.go (about)

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