github.com/aaabigfish/gopkg@v1.1.0/crypto/ecies.go (about)

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