Add 'crypto/ecies/' from commit '7c0f4a9b18d992166452d8cd32caaefd92b26386'

git-subtree-dir: crypto/ecies
git-subtree-mainline: 49a739c8d6
git-subtree-split: 7c0f4a9b18
This commit is contained in:
obscuren 2015-02-13 23:45:38 +01:00
commit 396f1a0a33
7 changed files with 1703 additions and 0 deletions

24
crypto/ecies/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*~

28
crypto/ecies/LICENSE Normal file
View File

@ -0,0 +1,28 @@
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.

94
crypto/ecies/README Normal file
View File

@ -0,0 +1,94 @@
# NOTE
This implementation is direct fork of Kylom's implementation. I claim no authorship over this code apart from some minor modifications.
Please be aware this code **has not yet been reviewed**.
ecies implements the Elliptic Curve Integrated Encryption Scheme.
The package is designed to be compliant with the appropriate NIST
standards, and therefore doesn't support the full SEC 1 algorithm set.
STATUS:
ecies should be ready for use. The ASN.1 support is only complete so
far as to supported the listed algorithms before.
CAVEATS
1. CMAC support is currently not present.
SUPPORTED ALGORITHMS
SYMMETRIC CIPHERS HASH FUNCTIONS
AES128 SHA-1
AES192 SHA-224
AES256 SHA-256
SHA-384
ELLIPTIC CURVE SHA-512
P256
P384 KEY DERIVATION FUNCTION
P521 NIST SP 800-65a Concatenation KDF
Curve P224 isn't supported because it does not provide a minimum security
level of AES128 with HMAC-SHA1. According to NIST SP 800-57, the security
level of P224 is 112 bits of security. Symmetric ciphers use CTR-mode;
message tags are computed using HMAC-<HASH> function.
CURVE SELECTION
According to NIST SP 800-57, the following curves should be selected:
+----------------+-------+
| SYMMETRIC SIZE | CURVE |
+----------------+-------+
| 128-bit | P256 |
+----------------+-------+
| 192-bit | P384 |
+----------------+-------+
| 256-bit | P521 |
+----------------+-------+
TODO
1. Look at serialising the parameters with the SEC 1 ASN.1 module.
2. Validate ASN.1 formats with SEC 1.
TEST VECTORS
The only test vectors I've found so far date from 1993, predating AES
and including only 163-bit curves. Therefore, there are no published
test vectors to compare to.
LICENSE
ecies is released under the same license as the Go source code. See the
LICENSE file for details.
REFERENCES
* SEC (Standard for Efficient Cryptography) 1, version 2.0: Elliptic
Curve Cryptography; Certicom, May 2009.
http://www.secg.org/sec1-v2.pdf
* GEC (Guidelines for Efficient Cryptography) 2, version 0.3: Test
Vectors for SEC 1; Certicom, September 1999.
http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf
* NIST SP 800-56a: Recommendation for Pair-Wise Key Establishment Schemes
Using Discrete Logarithm Cryptography. National Institute of Standards
and Technology, May 2007.
http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
* Suite B Implementers Guide to NIST SP 800-56A. National Security
Agency, July 28, 2009.
http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf
* NIST SP 800-57: Recommendation for Key Management Part 1: General
(Revision 3). National Institute of Standards and Technology, July
2012.
http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf

556
crypto/ecies/asn1.go Normal file
View File

@ -0,0 +1,556 @@
package ecies
import (
"bytes"
"crypto"
"crypto/elliptic"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/asn1"
"encoding/pem"
"fmt"
"hash"
"math/big"
)
var (
secgScheme = []int{1, 3, 132, 1}
shaScheme = []int{2, 16, 840, 1, 101, 3, 4, 2}
ansiX962Scheme = []int{1, 2, 840, 10045}
x963Scheme = []int{1, 2, 840, 63, 0}
)
var ErrInvalidPrivateKey = fmt.Errorf("ecies: invalid private key")
func doScheme(base, v []int) asn1.ObjectIdentifier {
var oidInts asn1.ObjectIdentifier
oidInts = append(oidInts, base...)
return append(oidInts, v...)
}
// curve OID code taken from crypto/x509, including
// - oidNameCurve*
// - namedCurveFromOID
// - oidFromNamedCurve
// RFC 5480, 2.1.1.1. Named Curve
//
// secp224r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
//
// secp256r1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
// prime(1) 7 }
//
// secp384r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
//
// secp521r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
//
// NB: secp256r1 is equivalent to prime256v1
type secgNamedCurve asn1.ObjectIdentifier
var (
secgNamedCurveP224 = secgNamedCurve{1, 3, 132, 0, 33}
secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
rawCurveP224 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 3}
rawCurveP256 = []byte{6, 8, 4, 2, 1, 3, 4, 7, 2, 2, 0, 6, 6, 1, 3, 1, 7}
rawCurveP384 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 4}
rawCurveP521 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 5}
)
func rawCurve(curve elliptic.Curve) []byte {
switch curve {
case elliptic.P224():
return rawCurveP224
case elliptic.P256():
return rawCurveP256
case elliptic.P384():
return rawCurveP384
case elliptic.P521():
return rawCurveP521
default:
return nil
}
}
func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
if len(curve) != len(curve2) {
return false
}
for i, _ := range curve {
if curve[i] != curve2[i] {
return false
}
}
return true
}
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
switch {
case curve.Equal(secgNamedCurveP224):
return elliptic.P224()
case curve.Equal(secgNamedCurveP256):
return elliptic.P256()
case curve.Equal(secgNamedCurveP384):
return elliptic.P384()
case curve.Equal(secgNamedCurveP521):
return elliptic.P521()
}
return nil
}
func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
switch curve {
case elliptic.P224():
return secgNamedCurveP224, true
case elliptic.P256():
return secgNamedCurveP256, true
case elliptic.P384():
return secgNamedCurveP384, true
case elliptic.P521():
return secgNamedCurveP521, true
}
return nil, false
}
// asnAlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
// 5280, section 4.1.1.2.
type asnAlgorithmIdentifier struct {
Algorithm asn1.ObjectIdentifier
Parameters asn1.RawValue `asn1:"optional"`
}
func (a asnAlgorithmIdentifier) Cmp(b asnAlgorithmIdentifier) bool {
if len(a.Algorithm) != len(b.Algorithm) {
return false
}
for i, _ := range a.Algorithm {
if a.Algorithm[i] != b.Algorithm[i] {
return false
}
}
return true
}
type asnHashFunction asnAlgorithmIdentifier
var (
oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
oidSHA224 = doScheme(shaScheme, []int{4})
oidSHA256 = doScheme(shaScheme, []int{1})
oidSHA384 = doScheme(shaScheme, []int{2})
oidSHA512 = doScheme(shaScheme, []int{3})
)
func hashFromOID(oid asn1.ObjectIdentifier) func() hash.Hash {
switch {
case oid.Equal(oidSHA1):
return sha1.New
case oid.Equal(oidSHA224):
return sha256.New224
case oid.Equal(oidSHA256):
return sha256.New
case oid.Equal(oidSHA384):
return sha512.New384
case oid.Equal(oidSHA512):
return sha512.New
}
return nil
}
func oidFromHash(hash crypto.Hash) (asn1.ObjectIdentifier, bool) {
switch hash {
case crypto.SHA1:
return oidSHA1, true
case crypto.SHA224:
return oidSHA224, true
case crypto.SHA256:
return oidSHA256, true
case crypto.SHA384:
return oidSHA384, true
case crypto.SHA512:
return oidSHA512, true
default:
return nil, false
}
}
var (
asnAlgoSHA1 = asnHashFunction{
Algorithm: oidSHA1,
}
asnAlgoSHA224 = asnHashFunction{
Algorithm: oidSHA224,
}
asnAlgoSHA256 = asnHashFunction{
Algorithm: oidSHA256,
}
asnAlgoSHA384 = asnHashFunction{
Algorithm: oidSHA384,
}
asnAlgoSHA512 = asnHashFunction{
Algorithm: oidSHA512,
}
)
// type ASNasnSubjectPublicKeyInfo struct {
//
// }
//
type asnSubjectPublicKeyInfo struct {
Algorithm asn1.ObjectIdentifier
PublicKey asn1.BitString
Supplements ecpksSupplements `asn1:"optional"`
}
type asnECPKAlgorithms struct {
Type asn1.ObjectIdentifier
}
var idPublicKeyType = doScheme(ansiX962Scheme, []int{2})
var idEcPublicKey = doScheme(idPublicKeyType, []int{1})
var idEcPublicKeySupplemented = doScheme(idPublicKeyType, []int{0})
func curveToRaw(curve elliptic.Curve) (rv asn1.RawValue, ok bool) {
switch curve {
case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
raw := rawCurve(curve)
return asn1.RawValue{
Tag: 30,
Bytes: raw[2:],
FullBytes: raw,
}, true
default:
return rv, false
}
}
func asnECPublicKeyType(curve elliptic.Curve) (algo asnAlgorithmIdentifier, ok bool) {
raw, ok := curveToRaw(curve)
if !ok {
return
} else {
return asnAlgorithmIdentifier{Algorithm: idEcPublicKey,
Parameters: raw}, true
}
}
type asnECPrivKeyVer int
var asnECPrivKeyVer1 asnECPrivKeyVer = 1
type asnPrivateKey struct {
Version asnECPrivKeyVer
Private []byte
Curve secgNamedCurve `asn1:"optional"`
Public asn1.BitString
}
var asnECDH = doScheme(secgScheme, []int{12})
type asnECDHAlgorithm asnAlgorithmIdentifier
var (
dhSinglePass_stdDH_sha1kdf = asnECDHAlgorithm{
Algorithm: doScheme(x963Scheme, []int{2}),
}
dhSinglePass_stdDH_sha256kdf = asnECDHAlgorithm{
Algorithm: doScheme(secgScheme, []int{11, 1}),
}
dhSinglePass_stdDH_sha384kdf = asnECDHAlgorithm{
Algorithm: doScheme(secgScheme, []int{11, 2}),
}
dhSinglePass_stdDH_sha224kdf = asnECDHAlgorithm{
Algorithm: doScheme(secgScheme, []int{11, 0}),
}
dhSinglePass_stdDH_sha512kdf = asnECDHAlgorithm{
Algorithm: doScheme(secgScheme, []int{11, 3}),
}
)
func (a asnECDHAlgorithm) Cmp(b asnECDHAlgorithm) bool {
if len(a.Algorithm) != len(b.Algorithm) {
return false
}
for i, _ := range a.Algorithm {
if a.Algorithm[i] != b.Algorithm[i] {
return false
}
}
return true
}
// asnNISTConcatenation is the only supported KDF at this time.
type asnKeyDerivationFunction asnAlgorithmIdentifier
var asnNISTConcatenationKDF = asnKeyDerivationFunction{
Algorithm: doScheme(secgScheme, []int{17, 1}),
}
func (a asnKeyDerivationFunction) Cmp(b asnKeyDerivationFunction) bool {
if len(a.Algorithm) != len(b.Algorithm) {
return false
}
for i, _ := range a.Algorithm {
if a.Algorithm[i] != b.Algorithm[i] {
return false
}
}
return true
}
var eciesRecommendedParameters = doScheme(secgScheme, []int{7})
var eciesSpecifiedParameters = doScheme(secgScheme, []int{8})
type asnECIESParameters struct {
KDF asnKeyDerivationFunction `asn1:"optional"`
Sym asnSymmetricEncryption `asn1:"optional"`
MAC asnMessageAuthenticationCode `asn1:"optional"`
}
type asnSymmetricEncryption asnAlgorithmIdentifier
var (
aes128CTRinECIES = asnSymmetricEncryption{
Algorithm: doScheme(secgScheme, []int{21, 0}),
}
aes192CTRinECIES = asnSymmetricEncryption{
Algorithm: doScheme(secgScheme, []int{21, 1}),
}
aes256CTRinECIES = asnSymmetricEncryption{
Algorithm: doScheme(secgScheme, []int{21, 2}),
}
)
func (a asnSymmetricEncryption) Cmp(b asnSymmetricEncryption) bool {
if len(a.Algorithm) != len(b.Algorithm) {
return false
}
for i, _ := range a.Algorithm {
if a.Algorithm[i] != b.Algorithm[i] {
return false
}
}
return true
}
type asnMessageAuthenticationCode asnAlgorithmIdentifier
var (
hmacFull = asnMessageAuthenticationCode{
Algorithm: doScheme(secgScheme, []int{22}),
}
)
func (a asnMessageAuthenticationCode) Cmp(b asnMessageAuthenticationCode) bool {
if len(a.Algorithm) != len(b.Algorithm) {
return false
}
for i, _ := range a.Algorithm {
if a.Algorithm[i] != b.Algorithm[i] {
return false
}
}
return true
}
type ecpksSupplements struct {
ECDomain secgNamedCurve
ECCAlgorithms eccAlgorithmSet
}
type eccAlgorithmSet struct {
ECDH asnECDHAlgorithm `asn1:"optional"`
ECIES asnECIESParameters `asn1:"optional"`
}
func marshalSubjectPublicKeyInfo(pub *PublicKey) (subj asnSubjectPublicKeyInfo, err error) {
subj.Algorithm = idEcPublicKeySupplemented
curve, ok := oidFromNamedCurve(pub.Curve)
if !ok {
err = ErrInvalidPublicKey
return
}
subj.Supplements.ECDomain = curve
if pub.Params != nil {
subj.Supplements.ECCAlgorithms.ECDH = paramsToASNECDH(pub.Params)
subj.Supplements.ECCAlgorithms.ECIES = paramsToASNECIES(pub.Params)
}
pubkey := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
subj.PublicKey = asn1.BitString{
BitLength: len(pubkey) * 8,
Bytes: pubkey,
}
return
}
// Encode a public key to DER format.
func MarshalPublic(pub *PublicKey) ([]byte, error) {
subj, err := marshalSubjectPublicKeyInfo(pub)
if err != nil {
return nil, err
}
return asn1.Marshal(subj)
}
// Decode a DER-encoded public key.
func UnmarshalPublic(in []byte) (pub *PublicKey, err error) {
var subj asnSubjectPublicKeyInfo
if _, err = asn1.Unmarshal(in, &subj); err != nil {
return
}
if !subj.Algorithm.Equal(idEcPublicKeySupplemented) {
err = ErrInvalidPublicKey
return
}
pub = new(PublicKey)
pub.Curve = namedCurveFromOID(subj.Supplements.ECDomain)
x, y := elliptic.Unmarshal(pub.Curve, subj.PublicKey.Bytes)
if x == nil {
err = ErrInvalidPublicKey
return
}
pub.X = x
pub.Y = y
pub.Params = new(ECIESParams)
asnECIEStoParams(subj.Supplements.ECCAlgorithms.ECIES, pub.Params)
asnECDHtoParams(subj.Supplements.ECCAlgorithms.ECDH, pub.Params)
if pub.Params == nil {
if pub.Params = ParamsFromCurve(pub.Curve); pub.Params == nil {
err = ErrInvalidPublicKey
}
}
return
}
func marshalPrivateKey(prv *PrivateKey) (ecprv asnPrivateKey, err error) {
ecprv.Version = asnECPrivKeyVer1
ecprv.Private = prv.D.Bytes()
var ok bool
ecprv.Curve, ok = oidFromNamedCurve(prv.PublicKey.Curve)
if !ok {
err = ErrInvalidPrivateKey
return
}
var pub []byte
if pub, err = MarshalPublic(&prv.PublicKey); err != nil {
return
} else {
ecprv.Public = asn1.BitString{
BitLength: len(pub) * 8,
Bytes: pub,
}
}
return
}
// Encode a private key to DER format.
func MarshalPrivate(prv *PrivateKey) ([]byte, error) {
ecprv, err := marshalPrivateKey(prv)
if err != nil {
return nil, err
}
return asn1.Marshal(ecprv)
}
// Decode a private key from a DER-encoded format.
func UnmarshalPrivate(in []byte) (prv *PrivateKey, err error) {
var ecprv asnPrivateKey
if _, err = asn1.Unmarshal(in, &ecprv); err != nil {
return
} else if ecprv.Version != asnECPrivKeyVer1 {
err = ErrInvalidPrivateKey
return
}
privateCurve := namedCurveFromOID(ecprv.Curve)
if privateCurve == nil {
err = ErrInvalidPrivateKey
return
}
prv = new(PrivateKey)
prv.D = new(big.Int).SetBytes(ecprv.Private)
if pub, err := UnmarshalPublic(ecprv.Public.Bytes); err != nil {
return nil, err
} else {
prv.PublicKey = *pub
}
return
}
// Export a public key to PEM format.
func ExportPublicPEM(pub *PublicKey) (out []byte, err error) {
der, err := MarshalPublic(pub)
if err != nil {
return
}
var block pem.Block
block.Type = "ELLIPTIC CURVE PUBLIC KEY"
block.Bytes = der
buf := new(bytes.Buffer)
err = pem.Encode(buf, &block)
if err != nil {
return
} else {
out = buf.Bytes()
}
return
}
// Export a private key to PEM format.
func ExportPrivatePEM(prv *PrivateKey) (out []byte, err error) {
der, err := MarshalPrivate(prv)
if err != nil {
return
}
var block pem.Block
block.Type = "ELLIPTIC CURVE PRIVATE KEY"
block.Bytes = der
buf := new(bytes.Buffer)
err = pem.Encode(buf, &block)
if err != nil {
return
} else {
out = buf.Bytes()
}
return
}
// Import a PEM-encoded public key.
func ImportPublicPEM(in []byte) (pub *PublicKey, err error) {
p, _ := pem.Decode(in)
if p == nil || p.Type != "ELLIPTIC CURVE PUBLIC KEY" {
return nil, ErrInvalidPublicKey
}
pub, err = UnmarshalPublic(p.Bytes)
return
}
// Import a PEM-encoded private key.
func ImportPrivatePEM(in []byte) (prv *PrivateKey, err error) {
p, _ := pem.Decode(in)
if p == nil || p.Type != "ELLIPTIC CURVE PRIVATE KEY" {
return nil, ErrInvalidPrivateKey
}
prv, err = UnmarshalPrivate(p.Bytes)
return
}

331
crypto/ecies/ecies.go Normal file
View File

@ -0,0 +1,331 @@
package ecies
import (
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/subtle"
"fmt"
"hash"
"io"
"math/big"
)
var (
ErrImport = fmt.Errorf("ecies: failed to import key")
ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters")
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")
)
// 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 {
return &ecdsa.PublicKey{pub.Curve, pub.X, pub.Y}
}
// 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()
return &ecdsa.PrivateKey{*pubECDSA, prv.D}
}
// 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,
// the recommended default paramters for the key will be chosen.
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 {
return nil, ErrInvalidCurve
}
if skLen+macLen > MaxSharedKeyLength(pub) {
return nil, ErrSharedKeyTooBig
}
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
if x == nil {
return nil, ErrSharedKeyIsPointAtInfinity
}
sk = make([]byte, skLen+macLen)
skBytes := x.Bytes()
copy(sk[len(sk)-len(skBytes):], skBytes)
return sk, nil
}
var (
ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
)
var (
big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
)
func incCounter(ctr []byte) {
if ctr[3]++; ctr[3] != 0 {
return
} else if ctr[2]++; ctr[2] != 0 {
return
} else if ctr[1]++; ctr[1] != 0 {
return
} else if ctr[0]++; ctr[0] != 0 {
return
}
return
}
// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
if s1 == nil {
s1 = make([]byte, 0)
}
reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
fmt.Println(big2To32M1)
return nil, ErrKeyDataTooLong
}
counter := []byte{0, 0, 0, 1}
k = make([]byte, 0)
for i := 0; i <= reps; i++ {
hash.Write(counter)
hash.Write(z)
hash.Write(s1)
k = append(k, hash.Sum(nil)...)
hash.Reset()
incCounter(counter)
}
k = k[:kdLen]
return
}
// 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 {
if shared == nil {
shared = make([]byte, 0)
}
mac := hmac.New(hash, km)
mac.Write(msg)
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
// parameters.
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
func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) {
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
}
// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. If
// the shared information parameters aren't being used, they should be
// nil.
func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
params := pub.Params
if params == nil {
if params = ParamsFromCurve(pub.Curve); params == nil {
err = ErrUnsupportedECIESParameters
return
}
}
R, err := GenerateKey(rand, pub.Curve, params)
if err != nil {
return
}
hash := params.Hash()
z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
if err != nil {
return
}
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
if err != nil {
return
}
Ke := K[:params.KeyLen]
Km := K[params.KeyLen:]
hash.Write(Km)
Km = hash.Sum(nil)
hash.Reset()
em, err := symEncrypt(rand, params, Ke, m)
if err != nil || len(em) <= params.BlockSize {
return
}
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)
return
}
// Decrypt decrypts an ECIES ciphertext.
func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) {
if c == nil || len(c) == 0 {
err = ErrInvalidMessage
return
}
params := prv.PublicKey.Params
if params == nil {
if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
err = ErrUnsupportedECIESParameters
return
}
}
hash := params.Hash()
var (
rLen int
hLen int = hash.Size()
mStart int
mEnd int
)
switch c[0] {
case 2, 3, 4:
rLen = ((prv.PublicKey.Curve.Params().BitSize + 7) / 4)
if len(c) < (rLen + hLen + 1) {
err = ErrInvalidMessage
return
}
default:
err = ErrInvalidPublicKey
return
}
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 {
err = ErrInvalidPublicKey
return
}
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
if err != nil {
return
}
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
if err != nil {
return
}
Ke := K[:params.KeyLen]
Km := K[params.KeyLen:]
hash.Write(Km)
Km = hash.Sum(nil)
hash.Reset()
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
err = ErrInvalidMessage
return
}
m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd])
return
}

489
crypto/ecies/ecies_test.go Normal file
View File

@ -0,0 +1,489 @@
package ecies
import (
"bytes"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"flag"
"fmt"
"io/ioutil"
"testing"
)
var dumpEnc bool
func init() {
flDump := flag.Bool("dump", false, "write encrypted test message to file")
flag.Parse()
dumpEnc = *flDump
}
// Ensure the KDF generates appropriately sized keys.
func TestKDF(t *testing.T) {
msg := []byte("Hello, world")
h := sha256.New()
k, err := concatKDF(h, msg, nil, 64)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if len(k) != 64 {
fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n",
len(k))
t.FailNow()
}
}
var skLen int
var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")
// cmpParams compares a set of ECIES parameters. We assume, as per the
// docs, that AES is the only supported symmetric encryption algorithm.
func cmpParams(p1, p2 *ECIESParams) bool {
if p1.hashAlgo != p2.hashAlgo {
return false
} else if p1.KeyLen != p2.KeyLen {
return false
} else if p1.BlockSize != p2.BlockSize {
return false
}
return true
}
// cmpPublic returns true if the two public keys represent the same pojnt.
func cmpPublic(pub1, pub2 PublicKey) bool {
if pub1.X == nil || pub1.Y == nil {
fmt.Println(ErrInvalidPublicKey.Error())
return false
}
if pub2.X == nil || pub2.Y == nil {
fmt.Println(ErrInvalidPublicKey.Error())
return false
}
pub1Out := elliptic.Marshal(pub1.Curve, pub1.X, pub1.Y)
pub2Out := elliptic.Marshal(pub2.Curve, pub2.X, pub2.Y)
return bytes.Equal(pub1Out, pub2Out)
}
// cmpPrivate returns true if the two private keys are the same.
func cmpPrivate(prv1, prv2 *PrivateKey) bool {
if prv1 == nil || prv1.D == nil {
return false
} else if prv2 == nil || prv2.D == nil {
return false
} else if prv1.D.Cmp(prv2.D) != 0 {
return false
} else {
return cmpPublic(prv1.PublicKey, prv2.PublicKey)
}
}
// Validate the ECDH component.
func TestSharedKey(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if !bytes.Equal(sk1, sk2) {
fmt.Println(ErrBadSharedKeys.Error())
t.FailNow()
}
}
// Verify that the key generation code fails when too much key data is
// requested.
func TestTooBigSharedKey(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
_, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
}
_, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
}
}
// Ensure a public key can be successfully marshalled and unmarshalled, and
// that the decoded key is the same as the original.
func TestMarshalPublic(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
out, err := MarshalPublic(&prv.PublicKey)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
pub, err := UnmarshalPublic(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if !cmpPublic(prv.PublicKey, *pub) {
fmt.Println("ecies: failed to unmarshal public key")
t.FailNow()
}
}
// Ensure that a private key can be encoded into DER format, and that
// the resulting key is properly parsed back into a public key.
func TestMarshalPrivate(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
out, err := MarshalPrivate(prv)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if dumpEnc {
ioutil.WriteFile("test.out", out, 0644)
}
prv2, err := UnmarshalPrivate(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if !cmpPrivate(prv, prv2) {
fmt.Println("ecdh: private key import failed")
t.FailNow()
}
}
// Ensure that a private key can be successfully encoded to PEM format, and
// the resulting key is properly parsed back in.
func TestPrivatePEM(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
out, err := ExportPrivatePEM(prv)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if dumpEnc {
ioutil.WriteFile("test.key", out, 0644)
}
prv2, err := ImportPrivatePEM(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
} else if !cmpPrivate(prv, prv2) {
fmt.Println("ecdh: import from PEM failed")
t.FailNow()
}
}
// Ensure that a public key can be successfully encoded to PEM format, and
// the resulting key is properly parsed back in.
func TestPublicPEM(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
out, err := ExportPublicPEM(&prv.PublicKey)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if dumpEnc {
ioutil.WriteFile("test.pem", out, 0644)
}
pub2, err := ImportPublicPEM(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
} else if !cmpPublic(prv.PublicKey, *pub2) {
fmt.Println("ecdh: import from PEM failed")
t.FailNow()
}
}
// Benchmark the generation of P256 keys.
func BenchmarkGenerateKeyP256(b *testing.B) {
for i := 0; i < b.N; i++ {
if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil {
fmt.Println(err.Error())
b.FailNow()
}
}
}
// Benchmark the generation of P256 shared keys.
func BenchmarkGenSharedKeyP256(b *testing.B) {
prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
}
for i := 0; i < b.N; i++ {
_, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
}
}
}
// Verify that an encrypted message can be successfully decrypted.
func TestEncryptDecrypt(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if !bytes.Equal(pt, message) {
fmt.Println("ecies: plaintext doesn't match message")
t.FailNow()
}
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
if err == nil {
fmt.Println("ecies: encryption should not have succeeded")
t.FailNow()
}
}
// TestMarshalEncryption validates the encode/decode produces a valid
// ECIES encryption key.
func TestMarshalEncryption(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
out, err := MarshalPrivate(prv1)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
prv2, err := UnmarshalPrivate(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
if !bytes.Equal(pt, message) {
fmt.Println("ecies: plaintext doesn't match message")
t.FailNow()
}
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
}
type testCase struct {
Curve elliptic.Curve
Name string
Expected bool
}
var testCases = []testCase{
testCase{
Curve: elliptic.P224(),
Name: "P224",
Expected: false,
},
testCase{
Curve: elliptic.P256(),
Name: "P256",
Expected: true,
},
testCase{
Curve: elliptic.P384(),
Name: "P384",
Expected: true,
},
testCase{
Curve: elliptic.P521(),
Name: "P521",
Expected: true,
},
}
// Test parameter selection for each curve, and that P224 fails automatic
// parameter selection (see README for a discussion of P224). Ensures that
// selecting a set of parameters automatically for the given curve works.
func TestParamSelection(t *testing.T) {
for _, c := range testCases {
testParamSelection(t, c)
}
}
func testParamSelection(t *testing.T, c testCase) {
params := ParamsFromCurve(c.Curve)
if params == nil && c.Expected {
fmt.Printf("%s (%s)\n", ErrInvalidParams.Error(), c.Name)
t.FailNow()
} else if params != nil && !c.Expected {
fmt.Printf("ecies: parameters should be invalid (%s)\n",
c.Name)
t.FailNow()
}
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
t.FailNow()
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
t.FailNow()
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
if err != nil {
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
t.FailNow()
}
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
if err != nil {
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
t.FailNow()
}
if !bytes.Equal(pt, message) {
fmt.Printf("ecies: plaintext doesn't match message (%s)\n",
c.Name)
t.FailNow()
}
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
if err == nil {
fmt.Printf("ecies: encryption should not have succeeded (%s)\n",
c.Name)
t.FailNow()
}
}
// Ensure that the basic public key validation in the decryption operation
// works.
func TestBasicKeyValidation(t *testing.T) {
badBytes := []byte{0, 1, 5, 6, 7, 8, 9}
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}
for _, b := range badBytes {
ct[0] = b
_, err := prv.Decrypt(rand.Reader, ct, nil, nil)
if err != ErrInvalidPublicKey {
fmt.Println("ecies: validated an invalid key")
t.FailNow()
}
}
}

181
crypto/ecies/params.go Normal file
View File

@ -0,0 +1,181 @@
package ecies
// This file contains parameters for ECIES encryption, specifying the
// symmetric encryption and HMAC parameters.
import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
"crypto/sha256"
"crypto/sha512"
"fmt"
"hash"
)
// The default curve for this package is the NIST P256 curve, which
// provides security equivalent to AES-128.
var DefaultCurve = elliptic.P256()
var (
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
)
type ECIESParams struct {
Hash func() hash.Hash // hash function
hashAlgo crypto.Hash
Cipher func([]byte) (cipher.Block, error) // symmetric cipher
BlockSize int // block size of symmetric cipher
KeyLen int // length of symmetric key
}
// Standard ECIES parameters:
// * ECIES using AES128 and HMAC-SHA-256-16
// * ECIES using AES256 and HMAC-SHA-256-32
// * ECIES using AES256 and HMAC-SHA-384-48
// * ECIES using AES256 and HMAC-SHA-512-64
var (
ECIES_AES128_SHA256 = &ECIESParams{
Hash: sha256.New,
hashAlgo: crypto.SHA256,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 16,
}
ECIES_AES256_SHA256 = &ECIESParams{
Hash: sha256.New,
hashAlgo: crypto.SHA256,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
ECIES_AES256_SHA384 = &ECIESParams{
Hash: sha512.New384,
hashAlgo: crypto.SHA384,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
ECIES_AES256_SHA512 = &ECIESParams{
Hash: sha512.New,
hashAlgo: crypto.SHA512,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
)
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512,
}
func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
paramsFromCurve[curve] = params
}
// ParamsFromCurve selects parameters optimal for the selected elliptic curve.
// Only the curves P256, P384, and P512 are supported.
func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
return paramsFromCurve[curve]
/*
switch curve {
case elliptic.P256():
return ECIES_AES128_SHA256
case elliptic.P384():
return ECIES_AES256_SHA384
case elliptic.P521():
return ECIES_AES256_SHA512
default:
return nil
}
*/
}
// ASN.1 encode the ECIES parameters relevant to the encryption operations.
func paramsToASNECIES(params *ECIESParams) (asnParams asnECIESParameters) {
if nil == params {
return
}
asnParams.KDF = asnNISTConcatenationKDF
asnParams.MAC = hmacFull
switch params.KeyLen {
case 16:
asnParams.Sym = aes128CTRinECIES
case 24:
asnParams.Sym = aes192CTRinECIES
case 32:
asnParams.Sym = aes256CTRinECIES
}
return
}
// ASN.1 encode the ECIES parameters relevant to ECDH.
func paramsToASNECDH(params *ECIESParams) (algo asnECDHAlgorithm) {
switch params.hashAlgo {
case crypto.SHA224:
algo = dhSinglePass_stdDH_sha224kdf
case crypto.SHA256:
algo = dhSinglePass_stdDH_sha256kdf
case crypto.SHA384:
algo = dhSinglePass_stdDH_sha384kdf
case crypto.SHA512:
algo = dhSinglePass_stdDH_sha512kdf
}
return
}
// ASN.1 decode the ECIES parameters relevant to the encryption stage.
func asnECIEStoParams(asnParams asnECIESParameters, params *ECIESParams) {
if !asnParams.KDF.Cmp(asnNISTConcatenationKDF) {
params = nil
return
} else if !asnParams.MAC.Cmp(hmacFull) {
params = nil
return
}
switch {
case asnParams.Sym.Cmp(aes128CTRinECIES):
params.KeyLen = 16
params.BlockSize = 16
params.Cipher = aes.NewCipher
case asnParams.Sym.Cmp(aes192CTRinECIES):
params.KeyLen = 24
params.BlockSize = 16
params.Cipher = aes.NewCipher
case asnParams.Sym.Cmp(aes256CTRinECIES):
params.KeyLen = 32
params.BlockSize = 16
params.Cipher = aes.NewCipher
default:
params = nil
}
}
// ASN.1 decode the ECIES parameters relevant to ECDH.
func asnECDHtoParams(asnParams asnECDHAlgorithm, params *ECIESParams) {
if asnParams.Cmp(dhSinglePass_stdDH_sha224kdf) {
params.hashAlgo = crypto.SHA224
params.Hash = sha256.New224
} else if asnParams.Cmp(dhSinglePass_stdDH_sha256kdf) {
params.hashAlgo = crypto.SHA256
params.Hash = sha256.New
} else if asnParams.Cmp(dhSinglePass_stdDH_sha384kdf) {
params.hashAlgo = crypto.SHA384
params.Hash = sha512.New384
} else if asnParams.Cmp(dhSinglePass_stdDH_sha512kdf) {
params.hashAlgo = crypto.SHA512
params.Hash = sha512.New
} else {
params = nil
}
}