mirror of https://github.com/ethereum/go-ethereum
commit
dea6584018
@ -1,77 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/* |
||||
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC |
||||
2898 / PKCS #5 v2.0. |
||||
|
||||
A key derivation function is useful when encrypting data based on a password |
||||
or any other not-fully-random data. It uses a pseudorandom function to derive |
||||
a secure encryption key based on the password. |
||||
|
||||
While v2.0 of the standard defines only one pseudorandom function to use, |
||||
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved |
||||
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To |
||||
choose, you can pass the `New` functions from the different SHA packages to |
||||
pbkdf2.Key. |
||||
*/ |
||||
package pbkdf2 |
||||
|
||||
import ( |
||||
"crypto/hmac" |
||||
"hash" |
||||
) |
||||
|
||||
// Key derives a key from the password, salt and iteration count, returning a
|
||||
// []byte of length keylen that can be used as cryptographic key. The key is
|
||||
// derived based on the method described as PBKDF2 with the HMAC variant using
|
||||
// the supplied hash function.
|
||||
//
|
||||
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
|
||||
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||
// doing:
|
||||
//
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
//
|
||||
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||
// RFC.
|
||||
//
|
||||
// Using a higher iteration count will increase the cost of an exhaustive
|
||||
// search but will also make derivation proportionally slower.
|
||||
func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { |
||||
prf := hmac.New(h, password) |
||||
hashLen := prf.Size() |
||||
numBlocks := (keyLen + hashLen - 1) / hashLen |
||||
|
||||
var buf [4]byte |
||||
dk := make([]byte, 0, numBlocks*hashLen) |
||||
U := make([]byte, hashLen) |
||||
for block := 1; block <= numBlocks; block++ { |
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset() |
||||
prf.Write(salt) |
||||
buf[0] = byte(block >> 24) |
||||
buf[1] = byte(block >> 16) |
||||
buf[2] = byte(block >> 8) |
||||
buf[3] = byte(block) |
||||
prf.Write(buf[:4]) |
||||
dk = prf.Sum(dk) |
||||
T := dk[len(dk)-hashLen:] |
||||
copy(U, T) |
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ { |
||||
prf.Reset() |
||||
prf.Write(U) |
||||
U = U[:0] |
||||
U = prf.Sum(U) |
||||
for x := range U { |
||||
T[x] ^= U[x] |
||||
} |
||||
} |
||||
} |
||||
return dk[:keyLen] |
||||
} |
@ -1,157 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pbkdf2 |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto/sha1" |
||||
"crypto/sha256" |
||||
"hash" |
||||
"testing" |
||||
) |
||||
|
||||
type testVector struct { |
||||
password string |
||||
salt string |
||||
iter int |
||||
output []byte |
||||
} |
||||
|
||||
// Test vectors from RFC 6070, http://tools.ietf.org/html/rfc6070
|
||||
var sha1TestVectors = []testVector{ |
||||
{ |
||||
"password", |
||||
"salt", |
||||
1, |
||||
[]byte{ |
||||
0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, |
||||
0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, |
||||
0x2f, 0xe0, 0x37, 0xa6, |
||||
}, |
||||
}, |
||||
{ |
||||
"password", |
||||
"salt", |
||||
2, |
||||
[]byte{ |
||||
0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, |
||||
0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, |
||||
0xd8, 0xde, 0x89, 0x57, |
||||
}, |
||||
}, |
||||
{ |
||||
"password", |
||||
"salt", |
||||
4096, |
||||
[]byte{ |
||||
0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, |
||||
0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, |
||||
0x65, 0xa4, 0x29, 0xc1, |
||||
}, |
||||
}, |
||||
// // This one takes too long
|
||||
// {
|
||||
// "password",
|
||||
// "salt",
|
||||
// 16777216,
|
||||
// []byte{
|
||||
// 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
|
||||
// 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
|
||||
// 0x26, 0x34, 0xe9, 0x84,
|
||||
// },
|
||||
// },
|
||||
{ |
||||
"passwordPASSWORDpassword", |
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", |
||||
4096, |
||||
[]byte{ |
||||
0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, |
||||
0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, |
||||
0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, |
||||
0x38, |
||||
}, |
||||
}, |
||||
{ |
||||
"pass\000word", |
||||
"sa\000lt", |
||||
4096, |
||||
[]byte{ |
||||
0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, |
||||
0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
// Test vectors from
|
||||
// http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
|
||||
var sha256TestVectors = []testVector{ |
||||
{ |
||||
"password", |
||||
"salt", |
||||
1, |
||||
[]byte{ |
||||
0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, |
||||
0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, |
||||
0xa8, 0x65, 0x48, 0xc9, |
||||
}, |
||||
}, |
||||
{ |
||||
"password", |
||||
"salt", |
||||
2, |
||||
[]byte{ |
||||
0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, |
||||
0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0, |
||||
0x2a, 0x30, 0x3f, 0x8e, |
||||
}, |
||||
}, |
||||
{ |
||||
"password", |
||||
"salt", |
||||
4096, |
||||
[]byte{ |
||||
0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, |
||||
0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, |
||||
0x96, 0x28, 0x93, 0xa0, |
||||
}, |
||||
}, |
||||
{ |
||||
"passwordPASSWORDpassword", |
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", |
||||
4096, |
||||
[]byte{ |
||||
0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, |
||||
0x32, 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, |
||||
0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18, |
||||
0x1c, |
||||
}, |
||||
}, |
||||
{ |
||||
"pass\000word", |
||||
"sa\000lt", |
||||
4096, |
||||
[]byte{ |
||||
0x89, 0xb6, 0x9d, 0x05, 0x16, 0xf8, 0x29, 0x89, |
||||
0x3c, 0x69, 0x62, 0x26, 0x65, 0x0a, 0x86, 0x87, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
func testHash(t *testing.T, h func() hash.Hash, hashName string, vectors []testVector) { |
||||
for i, v := range vectors { |
||||
o := Key([]byte(v.password), []byte(v.salt), v.iter, len(v.output), h) |
||||
if !bytes.Equal(o, v.output) { |
||||
t.Errorf("%s %d: expected %x, got %x", hashName, i, v.output, o) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestWithHMACSHA1(t *testing.T) { |
||||
testHash(t, sha1.New, "SHA1", sha1TestVectors) |
||||
} |
||||
|
||||
func TestWithHMACSHA256(t *testing.T) { |
||||
testHash(t, sha256.New, "SHA256", sha256TestVectors) |
||||
} |
@ -1,24 +0,0 @@ |
||||
# 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 |
||||
|
||||
*~ |
@ -1,28 +0,0 @@ |
||||
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. |
@ -1,94 +0,0 @@ |
||||
# 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 Implementer’s 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 |
||||
|
@ -1,556 +0,0 @@ |
||||
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 |
||||
} |
@ -1,326 +0,0 @@ |
||||
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") |
||||
ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key is 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 { |
||||
err = ErrInvalidCurve |
||||
return |
||||
} |
||||
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) |
||||
if x == nil || (x.BitLen()+7)/8 < (skLen+macLen) { |
||||
err = ErrSharedKeyTooBig |
||||
return |
||||
} |
||||
sk = x.Bytes()[:skLen+macLen] |
||||
return |
||||
} |
||||
|
||||
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 |
||||
} |
@ -1,489 +0,0 @@ |
||||
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() |
||||
} |
||||
} |
||||
} |
@ -1,187 +0,0 @@ |
||||
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 |
||||
ECIES_AES256_SHA256 *ECIESParams |
||||
ECIES_AES256_SHA384 *ECIESParams |
||||
ECIES_AES256_SHA512 *ECIESParams |
||||
) |
||||
|
||||
func init() { |
||||
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 |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
<html> |
||||
<head> |
||||
<script src="../ext/bignumber.min.js"></script> |
||||
<script src="../ext/ethereum.js/dist/ethereum.js"></script> |
||||
|
||||
<script> |
||||
var web3 = require('web3'); |
||||
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545')); |
||||
var eth = web3.eth; |
||||
|
||||
function bomb() { |
||||
for (var i = 0; i < 200; i++) { |
||||
eth.transact({}) |
||||
} |
||||
} |
||||
</script> |
||||
</head> |
||||
|
||||
<body> |
||||
<button onclick="bomb();">BOOM!</button> |
||||
</body> |
||||
</html> |
@ -0,0 +1,34 @@ |
||||
package core |
||||
|
||||
import ( |
||||
"math/big" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/event" |
||||
) |
||||
|
||||
func proc() (*BlockProcessor, *ChainManager) { |
||||
db, _ := ethdb.NewMemDatabase() |
||||
var mux event.TypeMux |
||||
|
||||
chainMan := NewChainManager(db, &mux) |
||||
return NewBlockProcessor(db, nil, chainMan, &mux), chainMan |
||||
} |
||||
|
||||
func TestNumber(t *testing.T) { |
||||
bp, chain := proc() |
||||
block1 := chain.NewBlock(nil) |
||||
block1.Header().Number = big.NewInt(3) |
||||
|
||||
err := bp.ValidateBlock(block1, chain.Genesis()) |
||||
if err != BlockNumberErr { |
||||
t.Errorf("expected block number error") |
||||
} |
||||
|
||||
block1 = chain.NewBlock(nil) |
||||
err = bp.ValidateBlock(block1, chain.Genesis()) |
||||
if err == BlockNumberErr { |
||||
t.Errorf("didn't expect block number error") |
||||
} |
||||
} |
@ -0,0 +1,181 @@ |
||||
package number |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/ethutil" |
||||
) |
||||
|
||||
var tt256 = new(big.Int).Lsh(big.NewInt(1), 256) |
||||
var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) |
||||
var tt255 = new(big.Int).Lsh(big.NewInt(1), 255) |
||||
|
||||
func limitUnsigned256(x *Number) *Number { |
||||
x.num.And(x.num, tt256m1) |
||||
return x |
||||
} |
||||
|
||||
func limitSigned256(x *Number) *Number { |
||||
if x.num.Cmp(tt255) < 0 { |
||||
return x |
||||
} else { |
||||
x.num.Sub(x.num, tt256) |
||||
return x |
||||
} |
||||
} |
||||
|
||||
// Number function
|
||||
type Initialiser func(n int64) *Number |
||||
|
||||
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
|
||||
// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda
|
||||
// with the new Initialiser.
|
||||
type Number struct { |
||||
num *big.Int |
||||
limit func(n *Number) *Number |
||||
} |
||||
|
||||
// Returns a new initialiser for a new *Number without having to expose certain fields
|
||||
func NewInitialiser(limiter func(*Number) *Number) Initialiser { |
||||
return func(n int64) *Number { |
||||
return &Number{big.NewInt(n), limiter} |
||||
} |
||||
} |
||||
|
||||
// Return a Number with a UNSIGNED limiter up to 256 bits
|
||||
func Uint256(n int64) *Number { |
||||
return &Number{big.NewInt(n), limitUnsigned256} |
||||
} |
||||
|
||||
// Return a Number with a SIGNED limiter up to 256 bits
|
||||
func Int256(n int64) *Number { |
||||
return &Number{big.NewInt(n), limitSigned256} |
||||
} |
||||
|
||||
// Returns a Number with a SIGNED unlimited size
|
||||
func Big(n int64) *Number { |
||||
return &Number{big.NewInt(n), func(x *Number) *Number { return x }} |
||||
} |
||||
|
||||
// Sets i to sum of x+y
|
||||
func (i *Number) Add(x, y *Number) *Number { |
||||
i.num.Add(x.num, y.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to difference of x-y
|
||||
func (i *Number) Sub(x, y *Number) *Number { |
||||
i.num.Sub(x.num, y.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to product of x*y
|
||||
func (i *Number) Mul(x, y *Number) *Number { |
||||
i.num.Mul(x.num, y.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to the quotient prodject of x/y
|
||||
func (i *Number) Div(x, y *Number) *Number { |
||||
i.num.Div(x.num, y.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to x % y
|
||||
func (i *Number) Mod(x, y *Number) *Number { |
||||
i.num.Mod(x.num, y.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to x << s
|
||||
func (i *Number) Lsh(x *Number, s uint) *Number { |
||||
i.num.Lsh(x.num, s) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Sets i to x^y
|
||||
func (i *Number) Pow(x, y *Number) *Number { |
||||
i.num.Exp(x.num, y.num, big.NewInt(0)) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Setters
|
||||
|
||||
// Set x to i
|
||||
func (i *Number) Set(x *Number) *Number { |
||||
i.num.Set(x.num) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Set x bytes to i
|
||||
func (i *Number) SetBytes(x []byte) *Number { |
||||
i.num.SetBytes(x) |
||||
return i.limit(i) |
||||
} |
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
func (i *Number) Cmp(x *Number) int { |
||||
return i.num.Cmp(x.num) |
||||
} |
||||
|
||||
// Getters
|
||||
|
||||
// Returns the string representation of i
|
||||
func (i *Number) String() string { |
||||
return i.num.String() |
||||
} |
||||
|
||||
// Returns the byte representation of i
|
||||
func (i *Number) Bytes() []byte { |
||||
return i.num.Bytes() |
||||
} |
||||
|
||||
// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined.
|
||||
func (i *Number) Uint64() uint64 { |
||||
return i.num.Uint64() |
||||
} |
||||
|
||||
// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined.
|
||||
func (i *Number) Int64() int64 { |
||||
return i.num.Int64() |
||||
} |
||||
|
||||
// Returns the signed version of i
|
||||
func (i *Number) Int256() *Number { |
||||
return Int(0).Set(i) |
||||
} |
||||
|
||||
// Returns the unsigned version of i
|
||||
func (i *Number) Uint256() *Number { |
||||
return Uint(0).Set(i) |
||||
} |
||||
|
||||
// Returns the index of the first bit that's set to 1
|
||||
func (i *Number) FirstBitSet() int { |
||||
for j := 0; j < i.num.BitLen(); j++ { |
||||
if i.num.Bit(j) > 0 { |
||||
return j |
||||
} |
||||
} |
||||
|
||||
return i.num.BitLen() |
||||
} |
||||
|
||||
// Variables
|
||||
|
||||
var ( |
||||
Zero = Uint(0) |
||||
One = Uint(1) |
||||
Two = Uint(2) |
||||
MaxUint256 = Uint(0).SetBytes(ethutil.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) |
||||
|
||||
MinOne = Int(-1) |
||||
|
||||
// "typedefs"
|
||||
Uint = Uint256 |
||||
Int = Int256 |
||||
) |
@ -0,0 +1,92 @@ |
||||
package number |
||||
|
||||
import ( |
||||
"math/big" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/ethutil" |
||||
) |
||||
|
||||
func TestSet(t *testing.T) { |
||||
a := Uint(0) |
||||
b := Uint(10) |
||||
a.Set(b) |
||||
if a.num.Cmp(b.num) != 0 { |
||||
t.Error("didn't compare", a, b) |
||||
} |
||||
|
||||
c := Uint(0).SetBytes(ethutil.Hex2Bytes("0a")) |
||||
if c.num.Cmp(big.NewInt(10)) != 0 { |
||||
t.Error("c set bytes failed.") |
||||
} |
||||
} |
||||
|
||||
func TestInitialiser(t *testing.T) { |
||||
check := false |
||||
init := NewInitialiser(func(x *Number) *Number { |
||||
check = true |
||||
return x |
||||
}) |
||||
a := init(0).Add(init(1), init(2)) |
||||
if a.Cmp(init(3)) != 0 { |
||||
t.Error("expected 3. got", a) |
||||
} |
||||
if !check { |
||||
t.Error("expected limiter to be called") |
||||
} |
||||
} |
||||
|
||||
func TestGet(t *testing.T) { |
||||
a := Uint(10) |
||||
if a.Uint64() != 10 { |
||||
t.Error("expected to get 10. got", a.Uint64()) |
||||
} |
||||
|
||||
a = Uint(10) |
||||
if a.Int64() != 10 { |
||||
t.Error("expected to get 10. got", a.Int64()) |
||||
} |
||||
} |
||||
|
||||
func TestCmp(t *testing.T) { |
||||
a := Uint(10) |
||||
b := Uint(10) |
||||
c := Uint(11) |
||||
|
||||
if a.Cmp(b) != 0 { |
||||
t.Error("a b == 0 failed", a, b) |
||||
} |
||||
|
||||
if a.Cmp(c) >= 0 { |
||||
t.Error("a c < 0 failed", a, c) |
||||
} |
||||
|
||||
if c.Cmp(b) <= 0 { |
||||
t.Error("c b > 0 failed", c, b) |
||||
} |
||||
} |
||||
|
||||
func TestMaxArith(t *testing.T) { |
||||
a := Uint(0).Add(MaxUint256, One) |
||||
if a.Cmp(Zero) != 0 { |
||||
t.Error("expected max256 + 1 = 0 got", a) |
||||
} |
||||
|
||||
a = Uint(0).Sub(Uint(0), One) |
||||
if a.Cmp(MaxUint256) != 0 { |
||||
t.Error("expected 0 - 1 = max256 got", a) |
||||
} |
||||
|
||||
a = Int(0).Sub(Int(0), One) |
||||
if a.Cmp(MinOne) != 0 { |
||||
t.Error("expected 0 - 1 = -1 got", a) |
||||
} |
||||
} |
||||
|
||||
func TestConversion(t *testing.T) { |
||||
a := Int(-1) |
||||
b := a.Uint256() |
||||
if b.Cmp(MaxUint256) != 0 { |
||||
t.Error("expected -1 => unsigned to return max. got", b) |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
package rpc |
||||
|
||||
import ( |
||||
"sync" |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
func TestFilterClose(t *testing.T) { |
||||
api := &EthereumApi{ |
||||
logs: make(map[int]*logFilter), |
||||
messages: make(map[int]*whisperFilter), |
||||
quit: make(chan struct{}), |
||||
} |
||||
|
||||
filterTickerTime = 1 |
||||
api.logs[0] = &logFilter{} |
||||
api.messages[0] = &whisperFilter{} |
||||
var wg sync.WaitGroup |
||||
wg.Add(1) |
||||
go api.start() |
||||
go func() { |
||||
select { |
||||
case <-time.After(500 * time.Millisecond): |
||||
api.stop() |
||||
wg.Done() |
||||
} |
||||
}() |
||||
wg.Wait() |
||||
if len(api.logs) != 0 { |
||||
t.Error("expected logs to be empty") |
||||
} |
||||
|
||||
if len(api.messages) != 0 { |
||||
t.Error("expected messages to be empty") |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue