@ -35,6 +35,7 @@ import (
"crypto/elliptic"
"crypto/elliptic"
"crypto/hmac"
"crypto/hmac"
"crypto/subtle"
"crypto/subtle"
"encoding/binary"
"fmt"
"fmt"
"hash"
"hash"
"io"
"io"
@ -44,7 +45,6 @@ import (
var (
var (
ErrImport = fmt . Errorf ( "ecies: failed to import key" )
ErrImport = fmt . Errorf ( "ecies: failed to import key" )
ErrInvalidCurve = fmt . Errorf ( "ecies: invalid elliptic curve" )
ErrInvalidCurve = fmt . Errorf ( "ecies: invalid elliptic curve" )
ErrInvalidParams = fmt . Errorf ( "ecies: invalid ECIES parameters" )
ErrInvalidPublicKey = fmt . Errorf ( "ecies: invalid public key" )
ErrInvalidPublicKey = fmt . Errorf ( "ecies: invalid public key" )
ErrSharedKeyIsPointAtInfinity = fmt . Errorf ( "ecies: shared key is point at infinity" )
ErrSharedKeyIsPointAtInfinity = fmt . Errorf ( "ecies: shared key is point at infinity" )
ErrSharedKeyTooBig = fmt . Errorf ( "ecies: shared key params are too big" )
ErrSharedKeyTooBig = fmt . Errorf ( "ecies: shared key params are too big" )
@ -138,57 +138,39 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b
}
}
var (
var (
ErrKeyDataTooLong = fmt . Errorf ( "ecies: can't supply requested key data" )
ErrSharedTooLong = fmt . Errorf ( "ecies: shared secret is too long" )
ErrSharedTooLong = fmt . Errorf ( "ecies: shared secret is too long" )
ErrInvalidMessage = fmt . Errorf ( "ecies: invalid message" )
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
}
if ctr [ 2 ] ++ ; ctr [ 2 ] != 0 {
return
}
if ctr [ 1 ] ++ ; ctr [ 1 ] != 0 {
return
}
if ctr [ 0 ] ++ ; ctr [ 0 ] != 0 {
return
}
}
// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
// 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 ) {
func concatKDF ( hash hash . Hash , z , s1 [ ] byte , kdLen int ) [ ] byte {
if s1 == nil {
counterBytes := make ( [ ] byte , 4 )
s1 = make ( [ ] byte , 0 )
k := make ( [ ] byte , 0 , roundup ( kdLen , hash . Size ( ) ) )
}
for counter := uint32 ( 1 ) ; len ( k ) < kdLen ; counter ++ {
binary . BigEndian . PutUint32 ( counterBytes , counter )
reps := ( ( kdLen + 7 ) * 8 ) / ( hash . BlockSize ( ) * 8 )
hash . Reset ( )
if big . NewInt ( int64 ( reps ) ) . Cmp ( big2To32M1 ) > 0 {
hash . Write ( counterBytes )
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 ( z )
hash . Write ( s1 )
hash . Write ( s1 )
k = append ( k , hash . Sum ( nil ) ... )
k = hash . Sum ( k )
hash . Reset ( )
incCounter ( counter )
}
}
return k [ : kdLen ]
}
k = k [ : kdLen ]
// roundup rounds size up to the next multiple of blocksize.
return
func roundup ( size , blocksize int ) int {
return size + blocksize - ( size % blocksize )
}
// deriveKeys creates the encryption and MAC keys using concatKDF.
func deriveKeys ( hash hash . Hash , z , s1 [ ] byte , keyLen int ) ( Ke , Km [ ] byte ) {
K := concatKDF ( hash , z , s1 , 2 * keyLen )
Ke = K [ : keyLen ]
Km = K [ keyLen : ]
hash . Reset ( )
hash . Write ( Km )
Km = hash . Sum ( Km [ : 0 ] )
return Ke , Km
}
}
// messageTag computes the MAC of a message (called the tag) as per
// messageTag computes the MAC of a message (called the tag) as per
@ -209,7 +191,6 @@ func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
}
}
// symEncrypt carries out CTR encryption using the block cipher specified in the
// 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 ) {
func symEncrypt ( rand io . Reader , params * ECIESParams , key , m [ ] byte ) ( ct [ ] byte , err error ) {
c , err := params . Cipher ( key )
c , err := params . Cipher ( key )
if err != nil {
if err != nil {
@ -249,36 +230,27 @@ func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
// shared information parameters aren't being used, they should be nil.
// 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 ) {
func Encrypt ( rand io . Reader , pub * PublicKey , m , s1 , s2 [ ] byte ) ( ct [ ] byte , err error ) {
params := pub . Params
params , err := pubkeyParams ( pub )
if params == nil {
if err != nil {
if params = ParamsFromCurve ( pub . Curve ) ; params == nil {
return nil , err
err = ErrUnsupportedECIESParameters
return
}
}
}
R , err := GenerateKey ( rand , pub . Curve , params )
R , err := GenerateKey ( rand , pub . Curve , params )
if err != nil {
if err != nil {
return
return nil , err
}
}
hash := params . Hash ( )
z , err := R . GenerateShared ( pub , params . KeyLen , params . KeyLen )
z , err := R . GenerateShared ( pub , params . KeyLen , params . KeyLen )
if err != nil {
if err != nil {
return
return nil , err
}
K , err := concatKDF ( hash , z , s1 , params . KeyLen + params . KeyLen )
if err != nil {
return
}
}
Ke := K [ : params . KeyLen ]
Km := K [ params . KeyLen : ]
hash := params . Hash ( )
hash . Write ( Km )
Ke , Km := deriveKeys ( hash , z , s1 , params . KeyLen )
Km = hash . Sum ( nil )
hash . Reset ( )
em , err := symEncrypt ( rand , params , Ke , m )
em , err := symEncrypt ( rand , params , Ke , m )
if err != nil || len ( em ) <= params . BlockSize {
if err != nil || len ( em ) <= params . BlockSize {
return
return nil , err
}
}
d := messageTag ( params . Hash , Km , em , s2 )
d := messageTag ( params . Hash , Km , em , s2 )
@ -288,7 +260,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
copy ( ct , Rb )
copy ( ct , Rb )
copy ( ct [ len ( Rb ) : ] , em )
copy ( ct [ len ( Rb ) : ] , em )
copy ( ct [ len ( Rb ) + len ( em ) : ] , d )
copy ( ct [ len ( Rb ) + len ( em ) : ] , d )
return
return ct , nil
}
}
// Decrypt decrypts an ECIES ciphertext.
// Decrypt decrypts an ECIES ciphertext.
@ -296,13 +268,11 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
if len ( c ) == 0 {
if len ( c ) == 0 {
return nil , ErrInvalidMessage
return nil , ErrInvalidMessage
}
}
params := prv . PublicKey . Params
params , err := pubkeyParams ( & prv . PublicKey )
if params == nil {
if err != nil {
if params = ParamsFromCurve ( prv . PublicKey . Curve ) ; params == nil {
return nil , err
err = ErrUnsupportedECIESParameters
return
}
}
}
hash := params . Hash ( )
hash := params . Hash ( )
var (
var (
@ -316,12 +286,10 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
case 2 , 3 , 4 :
case 2 , 3 , 4 :
rLen = ( prv . PublicKey . Curve . Params ( ) . BitSize + 7 ) / 4
rLen = ( prv . PublicKey . Curve . Params ( ) . BitSize + 7 ) / 4
if len ( c ) < ( rLen + hLen + 1 ) {
if len ( c ) < ( rLen + hLen + 1 ) {
err = ErrInvalidMessage
return nil , ErrInvalidMessage
return
}
}
default :
default :
err = ErrInvalidPublicKey
return nil , ErrInvalidPublicKey
return
}
}
mStart = rLen
mStart = rLen
@ -331,36 +299,19 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
R . Curve = prv . PublicKey . Curve
R . Curve = prv . PublicKey . Curve
R . X , R . Y = elliptic . Unmarshal ( R . Curve , c [ : rLen ] )
R . X , R . Y = elliptic . Unmarshal ( R . Curve , c [ : rLen ] )
if R . X == nil {
if R . X == nil {
err = ErrInvalidPublicKey
return nil , ErrInvalidPublicKey
return
}
if ! R . Curve . IsOnCurve ( R . X , R . Y ) {
err = ErrInvalidCurve
return
}
}
z , err := prv . GenerateShared ( R , params . KeyLen , params . KeyLen )
z , err := prv . GenerateShared ( R , params . KeyLen , params . KeyLen )
if err != nil {
if err != nil {
return
return nil , err
}
}
Ke , Km := deriveKeys ( hash , z , s1 , params . KeyLen )
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 )
d := messageTag ( params . Hash , Km , c [ mStart : mEnd ] , s2 )
if subtle . ConstantTimeCompare ( c [ mEnd : ] , d ) != 1 {
if subtle . ConstantTimeCompare ( c [ mEnd : ] , d ) != 1 {
err = ErrInvalidMessage
return nil , ErrInvalidMessage
return
}
}
m , err = symDecrypt ( params , Ke , c [ mStart : mEnd ] )
return symDecrypt ( params , Ke , c [ mStart : mEnd ] )
return
}
}