github.com/core-coin/go-core/v2@v2.1.9/crypto/ecies/ecies_cgo.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 ecies
    31  
    32  import (
    33  	"crypto/aes"
    34  	"crypto/cipher"
    35  	"crypto/hmac"
    36  	"crypto/subtle"
    37  	"encoding/binary"
    38  	"fmt"
    39  	"hash"
    40  	"io"
    41  
    42  	"golang.org/x/crypto/sha3"
    43  
    44  	"github.com/core-coin/go-core/v2/crypto"
    45  )
    46  
    47  var (
    48  	ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
    49  	ErrInvalidMessage   = fmt.Errorf("ecies: invalid message")
    50  )
    51  
    52  // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
    53  func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte {
    54  	counterBytes := make([]byte, 4)
    55  	k := make([]byte, 0, roundup(kdLen, hash.Size()))
    56  	for counter := uint32(1); len(k) < kdLen; counter++ {
    57  		binary.BigEndian.PutUint32(counterBytes, counter)
    58  		hash.Reset()
    59  		hash.Write(counterBytes)
    60  		hash.Write(z)
    61  		hash.Write(s1)
    62  		k = hash.Sum(k)
    63  	}
    64  	return k[:kdLen]
    65  }
    66  
    67  // roundup rounds size up to the next multiple of blocksize.
    68  func roundup(size, blocksize int) int {
    69  	return size + blocksize - (size % blocksize)
    70  }
    71  
    72  // deriveKeys creates the encryption and MAC keys using concatKDF.
    73  func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) {
    74  	K := concatKDF(hash, z, s1, 2*keyLen)
    75  	Ke = K[:keyLen]
    76  	Km = K[keyLen:]
    77  	hash.Reset()
    78  	hash.Write(Km)
    79  	Km = hash.Sum(Km[:0])
    80  	return Ke, Km
    81  }
    82  
    83  // messageTag computes the MAC of a message (called the tag) as per
    84  // SEC 1, 3.5.
    85  func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
    86  	mac := hmac.New(hash, km)
    87  	mac.Write(msg)
    88  	mac.Write(shared)
    89  	tag := mac.Sum(nil)
    90  	return tag
    91  }
    92  
    93  // Generate an initialisation vector for CTR mode.
    94  func generateIV(rand io.Reader) (iv []byte, err error) {
    95  	iv = make([]byte, aes.BlockSize)
    96  	_, err = io.ReadFull(rand, iv)
    97  	return
    98  }
    99  
   100  // symEncrypt carries out CTR encryption using the block cipher specified in the
   101  func symEncrypt(rand io.Reader, key, m []byte) (ct []byte, err error) {
   102  	c, err := aes.NewCipher(key)
   103  	if err != nil {
   104  		return
   105  	}
   106  
   107  	iv, err := generateIV(rand)
   108  	if err != nil {
   109  		return
   110  	}
   111  	ctr := cipher.NewCTR(c, iv)
   112  
   113  	ct = make([]byte, len(m)+aes.BlockSize)
   114  	copy(ct, iv)
   115  	ctr.XORKeyStream(ct[aes.BlockSize:], m)
   116  	return
   117  }
   118  
   119  // symDecrypt carries out CTR decryption using the block cipher specified in
   120  // the parameters
   121  func symDecrypt(key, ct []byte) (m []byte, err error) {
   122  	c, err := aes.NewCipher(key)
   123  	if err != nil {
   124  		return
   125  	}
   126  
   127  	ctr := cipher.NewCTR(c, ct[:aes.BlockSize])
   128  
   129  	m = make([]byte, len(ct)-aes.BlockSize)
   130  	ctr.XORKeyStream(m, ct[aes.BlockSize:])
   131  	return
   132  }
   133  
   134  // Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.
   135  //
   136  // s1 and s2 contain shared information that is not part of the resulting
   137  // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
   138  // shared information parameters aren't being used, they should be nil.
   139  func Encrypt(rand io.Reader, pub *crypto.PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
   140  	R, err := crypto.GenerateKey(rand)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	z := crypto.ComputeSecret(R, pub)
   146  
   147  	hash := sha3.New256()
   148  	Ke, Km := deriveKeys(hash, z, s1, 16)
   149  
   150  	em, err := symEncrypt(rand, Ke, m)
   151  	if err != nil || len(em) <= aes.BlockSize {
   152  		return nil, err
   153  	}
   154  
   155  	d := messageTag(sha3.New256, Km, em, s2)
   156  
   157  	ct = make([]byte, len(R.PublicKey())+len(em)+len(d))
   158  	copy(ct, R.PublicKey()[:])
   159  	copy(ct[len(R.PublicKey()):], em)
   160  	copy(ct[len(R.PublicKey())+len(em):], d)
   161  	return ct, nil
   162  }
   163  
   164  // Decrypt decrypts an ECIES ciphertext.
   165  func Decrypt(prv *crypto.PrivateKey, c, s1, s2 []byte) (m []byte, err error) {
   166  	if len(c) == 0 {
   167  		return nil, ErrInvalidMessage
   168  	}
   169  
   170  	hash := sha3.New256()
   171  
   172  	var (
   173  		rLen   int = len(prv.PublicKey())
   174  		hLen   int = hash.Size()
   175  		mStart int = rLen
   176  		mEnd   int = len(c) - hLen
   177  	)
   178  
   179  	R, err := crypto.UnmarshalPubKey(c[:rLen])
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	if len(R) == 0 {
   184  		return nil, ErrInvalidPublicKey
   185  	}
   186  
   187  	z := crypto.ComputeSecret(prv, R)
   188  
   189  	Ke, Km := deriveKeys(hash, z, s1, 16)
   190  
   191  	d := messageTag(sha3.New256, Km, c[mStart:mEnd], s2)
   192  	if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
   193  		return nil, ErrInvalidMessage
   194  	}
   195  
   196  	return symDecrypt(Ke, c[mStart:mEnd])
   197  }