| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is> | 
					
						
							|  |  |  | // Copyright (c) 2012 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  | // modification, are permitted provided that the following conditions are | 
					
						
							|  |  |  | // met: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //    * Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  | // notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  | //    * Redistributions in binary form must reproduce the above | 
					
						
							|  |  |  | // copyright notice, this list of conditions and the following disclaimer | 
					
						
							|  |  |  | // in the documentation and/or other materials provided with the | 
					
						
							|  |  |  | // distribution. | 
					
						
							|  |  |  | //    * Neither the name of Google Inc. nor the names of its | 
					
						
							|  |  |  | // contributors may be used to endorse or promote products derived from | 
					
						
							|  |  |  | // this software without specific prior written permission. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
					
						
							|  |  |  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
					
						
							|  |  |  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
					
						
							|  |  |  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
					
						
							|  |  |  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | package ecies | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/cipher" | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							|  |  |  | 	"crypto/elliptic" | 
					
						
							|  |  |  | 	"crypto/hmac" | 
					
						
							|  |  |  | 	"crypto/subtle" | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	"encoding/binary" | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"hash" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2015-02-11 20:03:52 +01:00
										 |  |  | 	ErrImport                     = fmt.Errorf("ecies: failed to import key") | 
					
						
							|  |  |  | 	ErrInvalidCurve               = fmt.Errorf("ecies: invalid elliptic curve") | 
					
						
							|  |  |  | 	ErrInvalidPublicKey           = fmt.Errorf("ecies: invalid public key") | 
					
						
							|  |  |  | 	ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity") | 
					
						
							|  |  |  | 	ErrSharedKeyTooBig            = fmt.Errorf("ecies: shared key params are too big") | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PublicKey is a representation of an elliptic curve public key. | 
					
						
							|  |  |  | type PublicKey struct { | 
					
						
							|  |  |  | 	X *big.Int | 
					
						
							|  |  |  | 	Y *big.Int | 
					
						
							|  |  |  | 	elliptic.Curve | 
					
						
							|  |  |  | 	Params *ECIESParams | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Export an ECIES public key as an ECDSA public key. | 
					
						
							|  |  |  | func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { | 
					
						
							| 
									
										
										
										
											2016-04-15 11:06:57 +02:00
										 |  |  | 	return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Import an ECDSA public key as an ECIES public key. | 
					
						
							|  |  |  | func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { | 
					
						
							|  |  |  | 	return &PublicKey{ | 
					
						
							|  |  |  | 		X:      pub.X, | 
					
						
							|  |  |  | 		Y:      pub.Y, | 
					
						
							|  |  |  | 		Curve:  pub.Curve, | 
					
						
							|  |  |  | 		Params: ParamsFromCurve(pub.Curve), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PrivateKey is a representation of an elliptic curve private key. | 
					
						
							|  |  |  | type PrivateKey struct { | 
					
						
							|  |  |  | 	PublicKey | 
					
						
							|  |  |  | 	D *big.Int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Export an ECIES private key as an ECDSA private key. | 
					
						
							|  |  |  | func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { | 
					
						
							|  |  |  | 	pub := &prv.PublicKey | 
					
						
							|  |  |  | 	pubECDSA := pub.ExportECDSA() | 
					
						
							| 
									
										
										
										
											2016-04-15 11:06:57 +02:00
										 |  |  | 	return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Import an ECDSA private key as an ECIES private key. | 
					
						
							|  |  |  | func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { | 
					
						
							|  |  |  | 	pub := ImportECDSAPublic(&prv.PublicKey) | 
					
						
							|  |  |  | 	return &PrivateKey{*pub, prv.D} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generate an elliptic curve public / private keypair. If params is nil, | 
					
						
							| 
									
										
										
										
											2017-01-06 19:44:35 +02:00
										 |  |  | // the recommended default parameters for the key will be chosen. | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { | 
					
						
							|  |  |  | 	pb, x, y, err := elliptic.GenerateKey(curve, rand) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	prv = new(PrivateKey) | 
					
						
							|  |  |  | 	prv.PublicKey.X = x | 
					
						
							|  |  |  | 	prv.PublicKey.Y = y | 
					
						
							|  |  |  | 	prv.PublicKey.Curve = curve | 
					
						
							|  |  |  | 	prv.D = new(big.Int).SetBytes(pb) | 
					
						
							|  |  |  | 	if params == nil { | 
					
						
							|  |  |  | 		params = ParamsFromCurve(curve) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	prv.PublicKey.Params = params | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MaxSharedKeyLength returns the maximum length of the shared key the | 
					
						
							|  |  |  | // public key can produce. | 
					
						
							|  |  |  | func MaxSharedKeyLength(pub *PublicKey) int { | 
					
						
							|  |  |  | 	return (pub.Curve.Params().BitSize + 7) / 8 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ECDH key agreement method used to establish secret keys for encryption. | 
					
						
							|  |  |  | func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { | 
					
						
							|  |  |  | 	if prv.PublicKey.Curve != pub.Curve { | 
					
						
							| 
									
										
										
										
											2015-02-11 20:03:52 +01:00
										 |  |  | 		return nil, ErrInvalidCurve | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if skLen+macLen > MaxSharedKeyLength(pub) { | 
					
						
							|  |  |  | 		return nil, ErrSharedKeyTooBig | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-29 19:37:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) | 
					
						
							| 
									
										
										
										
											2015-02-11 20:03:52 +01:00
										 |  |  | 	if x == nil { | 
					
						
							|  |  |  | 		return nil, ErrSharedKeyIsPointAtInfinity | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-11 20:03:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sk = make([]byte, skLen+macLen) | 
					
						
							|  |  |  | 	skBytes := x.Bytes() | 
					
						
							|  |  |  | 	copy(sk[len(sk)-len(skBytes):], skBytes) | 
					
						
							|  |  |  | 	return sk, nil | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	ErrSharedTooLong  = fmt.Errorf("ecies: shared secret is too long") | 
					
						
							|  |  |  | 	ErrInvalidMessage = fmt.Errorf("ecies: invalid message") | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte { | 
					
						
							|  |  |  | 	counterBytes := make([]byte, 4) | 
					
						
							|  |  |  | 	k := make([]byte, 0, roundup(kdLen, hash.Size())) | 
					
						
							|  |  |  | 	for counter := uint32(1); len(k) < kdLen; counter++ { | 
					
						
							|  |  |  | 		binary.BigEndian.PutUint32(counterBytes, counter) | 
					
						
							|  |  |  | 		hash.Reset() | 
					
						
							|  |  |  | 		hash.Write(counterBytes) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 		hash.Write(z) | 
					
						
							|  |  |  | 		hash.Write(s1) | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		k = hash.Sum(k) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	return k[:kdLen] | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | // roundup rounds size up to the next multiple of blocksize. | 
					
						
							|  |  |  | func roundup(size, blocksize int) int { | 
					
						
							|  |  |  | 	return size + blocksize - (size % blocksize) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // deriveKeys creates the encryption and MAC keys using concatKDF. | 
					
						
							|  |  |  | func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) { | 
					
						
							|  |  |  | 	K := concatKDF(hash, z, s1, 2*keyLen) | 
					
						
							|  |  |  | 	Ke = K[:keyLen] | 
					
						
							|  |  |  | 	Km = K[keyLen:] | 
					
						
							|  |  |  | 	hash.Reset() | 
					
						
							|  |  |  | 	hash.Write(Km) | 
					
						
							|  |  |  | 	Km = hash.Sum(Km[:0]) | 
					
						
							|  |  |  | 	return Ke, Km | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // messageTag computes the MAC of a message (called the tag) as per | 
					
						
							|  |  |  | // SEC 1, 3.5. | 
					
						
							|  |  |  | func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte { | 
					
						
							|  |  |  | 	mac := hmac.New(hash, km) | 
					
						
							|  |  |  | 	mac.Write(msg) | 
					
						
							| 
									
										
										
										
											2016-02-09 20:05:49 +01:00
										 |  |  | 	mac.Write(shared) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	tag := mac.Sum(nil) | 
					
						
							|  |  |  | 	return tag | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generate an initialisation vector for CTR mode. | 
					
						
							|  |  |  | func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) { | 
					
						
							|  |  |  | 	iv = make([]byte, params.BlockSize) | 
					
						
							|  |  |  | 	_, err = io.ReadFull(rand, iv) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // symEncrypt carries out CTR encryption using the block cipher specified in the | 
					
						
							|  |  |  | func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) { | 
					
						
							|  |  |  | 	c, err := params.Cipher(key) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iv, err := generateIV(params, rand) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ctr := cipher.NewCTR(c, iv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ct = make([]byte, len(m)+params.BlockSize) | 
					
						
							|  |  |  | 	copy(ct, iv) | 
					
						
							|  |  |  | 	ctr.XORKeyStream(ct[params.BlockSize:], m) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // symDecrypt carries out CTR decryption using the block cipher specified in | 
					
						
							|  |  |  | // the parameters | 
					
						
							| 
									
										
										
										
											2018-03-26 03:46:18 -07:00
										 |  |  | func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	c, err := params.Cipher(key) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctr := cipher.NewCTR(c, ct[:params.BlockSize]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m = make([]byte, len(ct)-params.BlockSize) | 
					
						
							|  |  |  | 	ctr.XORKeyStream(m, ct[params.BlockSize:]) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 20:05:49 +01:00
										 |  |  | // Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // s1 and s2 contain shared information that is not part of the resulting | 
					
						
							|  |  |  | // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the | 
					
						
							|  |  |  | // shared information parameters aren't being used, they should be nil. | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	params, err := pubkeyParams(pub) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	R, err := GenerateKey(rand, pub.Curve, params) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hash := params.Hash() | 
					
						
							|  |  |  | 	Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	em, err := symEncrypt(rand, params, Ke, m) | 
					
						
							|  |  |  | 	if err != nil || len(em) <= params.BlockSize { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	d := messageTag(params.Hash, Km, em, s2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) | 
					
						
							|  |  |  | 	ct = make([]byte, len(Rb)+len(em)+len(d)) | 
					
						
							|  |  |  | 	copy(ct, Rb) | 
					
						
							|  |  |  | 	copy(ct[len(Rb):], em) | 
					
						
							|  |  |  | 	copy(ct[len(Rb)+len(em):], d) | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	return ct, nil | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Decrypt decrypts an ECIES ciphertext. | 
					
						
							| 
									
										
										
										
											2018-03-26 03:46:18 -07:00
										 |  |  | func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { | 
					
						
							| 
									
										
										
										
											2017-01-06 16:44:20 +01:00
										 |  |  | 	if len(c) == 0 { | 
					
						
							|  |  |  | 		return nil, ErrInvalidMessage | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	params, err := pubkeyParams(&prv.PublicKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	hash := params.Hash() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		rLen   int | 
					
						
							|  |  |  | 		hLen   int = hash.Size() | 
					
						
							|  |  |  | 		mStart int | 
					
						
							|  |  |  | 		mEnd   int | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch c[0] { | 
					
						
							|  |  |  | 	case 2, 3, 4: | 
					
						
							| 
									
										
										
										
											2018-01-03 15:14:47 +03:00
										 |  |  | 		rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 		if len(c) < (rLen + hLen + 1) { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 			return nil, ErrInvalidMessage | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, ErrInvalidPublicKey | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mStart = rLen | 
					
						
							|  |  |  | 	mEnd = len(c) - hLen | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	R := new(PublicKey) | 
					
						
							|  |  |  | 	R.Curve = prv.PublicKey.Curve | 
					
						
							|  |  |  | 	R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) | 
					
						
							|  |  |  | 	if R.X == nil { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, ErrInvalidPublicKey | 
					
						
							| 
									
										
										
										
											2015-04-07 17:40:51 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) | 
					
						
							|  |  |  | 	if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 		return nil, ErrInvalidMessage | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 05:57:24 -04:00
										 |  |  | 	return symDecrypt(params, Ke, c[mStart:mEnd]) | 
					
						
							| 
									
										
										
										
											2014-12-10 00:00:52 +01:00
										 |  |  | } |