github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/crypto/ecies/ecies.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:36</date>
    10  //</624450084968337409>
    11  
    12  //版权所有(c)2013 Kyle Isom<kyle@tyrfingr.is>
    13  //版权所有(c)2012 The Go作者。版权所有。
    14  //
    15  //以源和二进制形式重新分配和使用,有或无
    16  //允许修改,前提是以下条件
    17  //遇见:
    18  //
    19  //*源代码的再分配必须保留上述版权。
    20  //注意,此条件列表和以下免责声明。
    21  //*二进制形式的再分配必须复制上述内容
    22  //版权声明、此条件列表和以下免责声明
    23  //在提供的文件和/或其他材料中,
    24  //分布。
    25  //*无论是谷歌公司的名称还是其
    26  //贡献者可用于支持或推广源自
    27  //本软件未经事先明确书面许可。
    28  //
    29  //本软件由版权所有者和贡献者提供。
    30  //“原样”和任何明示或暗示的保证,包括但不包括
    31  //仅限于对适销性和适用性的暗示保证
    32  //不承认特定目的。在任何情况下,版权
    33  //所有人或出资人对任何直接、间接、附带的,
    34  //特殊、惩戒性或后果性损害(包括但不包括
    35  //仅限于采购替代货物或服务;使用损失,
    36  //数据或利润;或业务中断),无论如何引起的
    37  //责任理论,无论是合同责任、严格责任还是侵权责任。
    38  //(包括疏忽或其他)因使用不当而引起的
    39  //即使已告知此类损坏的可能性。
    40  
    41  package ecies
    42  
    43  import (
    44  	"crypto/cipher"
    45  	"crypto/ecdsa"
    46  	"crypto/elliptic"
    47  	"crypto/hmac"
    48  	"crypto/subtle"
    49  	"fmt"
    50  	"hash"
    51  	"io"
    52  	"math/big"
    53  )
    54  
    55  var (
    56  	ErrImport                     = fmt.Errorf("ecies: failed to import key")
    57  	ErrInvalidCurve               = fmt.Errorf("ecies: invalid elliptic curve")
    58  	ErrInvalidParams              = fmt.Errorf("ecies: invalid ECIES parameters")
    59  	ErrInvalidPublicKey           = fmt.Errorf("ecies: invalid public key")
    60  	ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
    61  	ErrSharedKeyTooBig            = fmt.Errorf("ecies: shared key params are too big")
    62  )
    63  
    64  //公钥是椭圆曲线公钥的表示形式。
    65  type PublicKey struct {
    66  	X *big.Int
    67  	Y *big.Int
    68  	elliptic.Curve
    69  	Params *ECIESParams
    70  }
    71  
    72  //将ECIES公钥导出为ECDSA公钥。
    73  func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
    74  	return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}
    75  }
    76  
    77  //将ECDSA公钥导入为特定的公钥。
    78  func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
    79  	return &PublicKey{
    80  		X:      pub.X,
    81  		Y:      pub.Y,
    82  		Curve:  pub.Curve,
    83  		Params: ParamsFromCurve(pub.Curve),
    84  	}
    85  }
    86  
    87  //private key是椭圆曲线私钥的表示。
    88  type PrivateKey struct {
    89  	PublicKey
    90  	D *big.Int
    91  }
    92  
    93  //Export an ECIES private key as an ECDSA private key.
    94  func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
    95  	pub := &prv.PublicKey
    96  	pubECDSA := pub.ExportECDSA()
    97  	return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}
    98  }
    99  
   100  //将ECDSA私钥导入为ECIES私钥。
   101  func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
   102  	pub := ImportECDSAPublic(&prv.PublicKey)
   103  	return &PrivateKey{*pub, prv.D}
   104  }
   105  
   106  //生成椭圆曲线公钥/私钥对。如果参数为零,
   107  //the recommended default parameters for the key will be chosen.
   108  func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
   109  	pb, x, y, err := elliptic.GenerateKey(curve, rand)
   110  	if err != nil {
   111  		return
   112  	}
   113  	prv = new(PrivateKey)
   114  	prv.PublicKey.X = x
   115  	prv.PublicKey.Y = y
   116  	prv.PublicKey.Curve = curve
   117  	prv.D = new(big.Int).SetBytes(pb)
   118  	if params == nil {
   119  		params = ParamsFromCurve(curve)
   120  	}
   121  	prv.PublicKey.Params = params
   122  	return
   123  }
   124  
   125  //MaxSharedKeyLength返回共享密钥的最大长度
   126  //可以生成公钥。
   127  func MaxSharedKeyLength(pub *PublicKey) int {
   128  	return (pub.Curve.Params().BitSize + 7) / 8
   129  }
   130  
   131  //用于建立加密密钥的ECDH密钥协议方法。
   132  func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
   133  	if prv.PublicKey.Curve != pub.Curve {
   134  		return nil, ErrInvalidCurve
   135  	}
   136  	if skLen+macLen > MaxSharedKeyLength(pub) {
   137  		return nil, ErrSharedKeyTooBig
   138  	}
   139  
   140  	x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
   141  	if x == nil {
   142  		return nil, ErrSharedKeyIsPointAtInfinity
   143  	}
   144  
   145  	sk = make([]byte, skLen+macLen)
   146  	skBytes := x.Bytes()
   147  	copy(sk[len(sk)-len(skBytes):], skBytes)
   148  	return sk, nil
   149  }
   150  
   151  var (
   152  	ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
   153  	ErrSharedTooLong  = fmt.Errorf("ecies: shared secret is too long")
   154  	ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
   155  )
   156  
   157  var (
   158  	big2To32   = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
   159  	big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
   160  )
   161  
   162  func incCounter(ctr []byte) {
   163  	if ctr[3]++; ctr[3] != 0 {
   164  		return
   165  	}
   166  	if ctr[2]++; ctr[2] != 0 {
   167  		return
   168  	}
   169  	if ctr[1]++; ctr[1] != 0 {
   170  		return
   171  	}
   172  	if ctr[0]++; ctr[0] != 0 {
   173  		return
   174  	}
   175  }
   176  
   177  //NIST SP 800-56串联密钥派生函数(见第5.8.1节)。
   178  func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
   179  	if s1 == nil {
   180  		s1 = make([]byte, 0)
   181  	}
   182  
   183  	reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
   184  	if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
   185  		fmt.Println(big2To32M1)
   186  		return nil, ErrKeyDataTooLong
   187  	}
   188  
   189  	counter := []byte{0, 0, 0, 1}
   190  	k = make([]byte, 0)
   191  
   192  	for i := 0; i <= reps; i++ {
   193  		hash.Write(counter)
   194  		hash.Write(z)
   195  		hash.Write(s1)
   196  		k = append(k, hash.Sum(nil)...)
   197  		hash.Reset()
   198  		incCounter(counter)
   199  	}
   200  
   201  	k = k[:kdLen]
   202  	return
   203  }
   204  
   205  //message tag根据
   206  //秒1,3.5。
   207  func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
   208  	mac := hmac.New(hash, km)
   209  	mac.Write(msg)
   210  	mac.Write(shared)
   211  	tag := mac.Sum(nil)
   212  	return tag
   213  }
   214  
   215  //为ctr模式生成初始化向量。
   216  func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
   217  	iv = make([]byte, params.BlockSize)
   218  	_, err = io.ReadFull(rand, iv)
   219  	return
   220  }
   221  
   222  //symeencrypt使用中指定的块密码执行ctr加密
   223  //参数。
   224  func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
   225  	c, err := params.Cipher(key)
   226  	if err != nil {
   227  		return
   228  	}
   229  
   230  	iv, err := generateIV(params, rand)
   231  	if err != nil {
   232  		return
   233  	}
   234  	ctr := cipher.NewCTR(c, iv)
   235  
   236  	ct = make([]byte, len(m)+params.BlockSize)
   237  	copy(ct, iv)
   238  	ctr.XORKeyStream(ct[params.BlockSize:], m)
   239  	return
   240  }
   241  
   242  //symDecrypt carries out CTR decryption using the block cipher specified in
   243  //参数
   244  func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
   245  	c, err := params.Cipher(key)
   246  	if err != nil {
   247  		return
   248  	}
   249  
   250  	ctr := cipher.NewCTR(c, ct[:params.BlockSize])
   251  
   252  	m = make([]byte, len(ct)-params.BlockSize)
   253  	ctr.XORKeyStream(m, ct[params.BlockSize:])
   254  	return
   255  }
   256  
   257  //Encrypt使用第1节5.1中指定的ECIES对消息进行加密。
   258  //
   259  //s1和s2包含不属于结果的共享信息
   260  //密文。s1被输入到键派生中,s2被输入到mac中。如果
   261  //未使用共享信息参数,它们应为零。
   262  func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
   263  	params := pub.Params
   264  	if params == nil {
   265  		if params = ParamsFromCurve(pub.Curve); params == nil {
   266  			err = ErrUnsupportedECIESParameters
   267  			return
   268  		}
   269  	}
   270  	R, err := GenerateKey(rand, pub.Curve, params)
   271  	if err != nil {
   272  		return
   273  	}
   274  
   275  	hash := params.Hash()
   276  	z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
   277  	if err != nil {
   278  		return
   279  	}
   280  	K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
   281  	if err != nil {
   282  		return
   283  	}
   284  	Ke := K[:params.KeyLen]
   285  	Km := K[params.KeyLen:]
   286  	hash.Write(Km)
   287  	Km = hash.Sum(nil)
   288  	hash.Reset()
   289  
   290  	em, err := symEncrypt(rand, params, Ke, m)
   291  	if err != nil || len(em) <= params.BlockSize {
   292  		return
   293  	}
   294  
   295  	d := messageTag(params.Hash, Km, em, s2)
   296  
   297  	Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
   298  	ct = make([]byte, len(Rb)+len(em)+len(d))
   299  	copy(ct, Rb)
   300  	copy(ct[len(Rb):], em)
   301  	copy(ct[len(Rb)+len(em):], d)
   302  	return
   303  }
   304  
   305  //解密-解密特定的密文。
   306  func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
   307  	if len(c) == 0 {
   308  		return nil, ErrInvalidMessage
   309  	}
   310  	params := prv.PublicKey.Params
   311  	if params == nil {
   312  		if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
   313  			err = ErrUnsupportedECIESParameters
   314  			return
   315  		}
   316  	}
   317  	hash := params.Hash()
   318  
   319  	var (
   320  		rLen   int
   321  		hLen   int = hash.Size()
   322  		mStart int
   323  		mEnd   int
   324  	)
   325  
   326  	switch c[0] {
   327  	case 2, 3, 4:
   328  		rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
   329  		if len(c) < (rLen + hLen + 1) {
   330  			err = ErrInvalidMessage
   331  			return
   332  		}
   333  	default:
   334  		err = ErrInvalidPublicKey
   335  		return
   336  	}
   337  
   338  	mStart = rLen
   339  	mEnd = len(c) - hLen
   340  
   341  	R := new(PublicKey)
   342  	R.Curve = prv.PublicKey.Curve
   343  	R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
   344  	if R.X == nil {
   345  		err = ErrInvalidPublicKey
   346  		return
   347  	}
   348  	if !R.Curve.IsOnCurve(R.X, R.Y) {
   349  		err = ErrInvalidCurve
   350  		return
   351  	}
   352  
   353  	z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
   354  	if err != nil {
   355  		return
   356  	}
   357  
   358  	K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
   359  	if err != nil {
   360  		return
   361  	}
   362  
   363  	Ke := K[:params.KeyLen]
   364  	Km := K[params.KeyLen:]
   365  	hash.Write(Km)
   366  	Km = hash.Sum(nil)
   367  	hash.Reset()
   368  
   369  	d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
   370  	if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
   371  		err = ErrInvalidMessage
   372  		return
   373  	}
   374  
   375  	m, err = symDecrypt(params, Ke, c[mStart:mEnd])
   376  	return
   377  }
   378