ecies

package module
v0.0.0-...-87b11b6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 9, 2023 License: MIT Imports: 14 Imported by: 0

README

ecies-go

version: v0.0.0

Installation

go get github.com/zytekaron/go-ecies

No release has been published yet, so if you want to download this library to test, you'll need to target a specific commit (see go docs: "Managing Dependencies")

Warnings

  • No cryptographic security guarantees!!!
  • No continued development guarantees
  • No API stability guarantees

Basically, don't use this library in anything but a testing project until I get it up to speed and it gets some stringent security auditing, which will probably never happen. Anything before a v1.0.0 release is to be considered highly unstable, buggy, dangerous, and all in all a really bad idea to use in production.

https://github.com/ecies is a good ECIES library suite you can use, including in Go; you just can't run it on arbitrary-length streams of data (if it doesn't fit in memory, you're forced to break up the message manually.)

Implementation Details

  • Uses the P-521 elliptic curve (subject to change)
  • AES-256-CTR / HMAC-SHA512 for stream encryption and MAC
  • HKDF-SHA512 for key derivation from ECDH shared secret

Primary Sources

License

ecies-go is licensed under the MIT License

Documentation

Index

Examples

Constants

View Source
const (
	// PublicKeyLengthCompressed is the length of the compressed public key when marshalled.
	// See elliptic.MarshalCompressed.
	PublicKeyLengthCompressed = 67

	// PublicKeyLengthUncompressed is the length of the uncompressed public key when marshalled.
	// See elliptic.Marshal.
	PublicKeyLengthUncompressed = 133
)
View Source
const StreamBufferSize = 4096

StreamBufferSize is the number of bytes to process at a time.

View Source
const StreamHMACLength = sha512.Size

StreamHMACLength is the length of the MAC used in HMAC-SHA512.

View Source
const StreamIVLength = 16

StreamIVLength is the length of the IV used in AES-CTR.

Variables

View Source
var ErrInvalidMAC = errors.New("invalid mac")
View Source
var ErrInvalidPublicKey = errors.New("invalid public key")

Functions

func CryptoKDF

func CryptoKDF(secret []byte) ([]byte, []byte, error)

CryptoKDF is used to generate AES and HMAC keys from a secret.

this function is used within the library since two keys are required for stream encryption, but only one secret (the shared ECDH key) exists.

func Decrypt

func Decrypt(privKey *PrivateKey, in io.Reader, out io.Writer) error

Decrypt decrypts an input stream with a given private key.

Example
// parse a private key, or use a new
// one generated using GenerateKey().
privateKey := ParsePrivateKey(privateKeyBytes)

// open file for decryption.
input, err := os.Open("secret.txt.enc")
if err != nil {
	log.Fatal(err)
}

// open file for output.
output, err := os.Create("secret.txt")
if err != nil {
	log.Fatal(err)
}

// decrypt secret.txt.enc into secret.txt using ecc private key.
err = Decrypt(privateKey, input, output)
if err != nil {
	log.Fatal(err)
}
Output:

func DecryptSimple

func DecryptSimple(privKey *PrivateKey, data []byte) ([]byte, error)

DecryptSimple decrypts a byte slice with a given private key.

Example
// parse a private key, or use a new
// one generated using GenerateKey().
privateKey := ParsePrivateKey(publicKeyBytes)

// decrypt data using the private key.
plaintext, err := DecryptSimple(privateKey, ciphertext)
if err != nil {
	log.Fatal(err)
}

// send or saveFile the output.
fmt.Println(string(plaintext))
Output:

func DecryptStream

func DecryptStream(in io.Reader, out io.Writer, aesKey, hmacKey []byte) error

DecryptStream decrypts an arbitrary-length input stream using AES-CTR (bit size determined by the passed AES key), and uses HMAC-SHA512 with the passed key for authentication.

func DecryptStreamSimple

func DecryptStreamSimple(in io.Reader, out io.Writer, secret []byte) error

DecryptStreamSimple decrypts an arbitrary-length input stream using AES-256-CTR, and uses HMAC-SHA512 for authentication.

The AES and HMAC keys are acquired from a KDF seeded with the provided secret.

func Encrypt

func Encrypt(pubKey *PublicKey, in io.Reader, out io.Writer) error

Encrypt encrypts an input stream for a given public key.

Example
// parse a public key, or use a new
// one generated using GenerateKey().
publicKey, err := ParsePublicKey(publicKeyBytes)
if err != nil {
	log.Fatal(err)
}

// open file for encryption.
input, err := os.Open("secret.txt")
if err != nil {
	log.Fatal(err)
}

// open file for output.
output, err := os.Create("secret.txt.enc")
if err != nil {
	log.Fatal(err)
}

// encrypt secret.txt into secret.txt.enc using ecc public key.
err = Encrypt(publicKey, input, output)
if err != nil {
	log.Fatal(err)
}
Output:

func EncryptSimple

func EncryptSimple(pubKey *PublicKey, data []byte) ([]byte, error)

EncryptSimple encrypts a byte slice for a given public key.

Example
// parse a public key, or use a new
// one generated using GenerateKey().
publicKey, err := ParsePublicKey(publicKeyBytes)
if err != nil {
	log.Fatal(err)
}

// encrypt data using the public key.
ciphertext, err := EncryptSimple(publicKey, []byte("my secret string"))
if err != nil {
	log.Fatal(err)
}

// send or store it. hex or base64 are good formats.
fmt.Println(hex.EncodeToString(ciphertext))
Output:

func EncryptStream

func EncryptStream(in io.Reader, out io.Writer, aesKey, hmacKey []byte) error

EncryptStream encrypts an arbitrary-length input stream using AES-CTR (bit size determined by the passed AES key), and uses HMAC-SHA512 with the passed key for authentication.

func EncryptStreamSimple

func EncryptStreamSimple(in io.Reader, out io.Writer, secret []byte) error

EncryptStreamSimple encrypts an arbitrary-length input stream using AES-256-CTR, and uses HMAC-SHA512 for authentication.

The AES and HMAC keys are acquired from a KDF seeded with the provided secret.

func SingleKDF

func SingleKDF(secret []byte) ([]byte, error)

SingleKDF is used to generate a single key that is safe to use as an encryption key from an otherwise unsafe key, such as an ECDH shared key.

Types

type PrivateKey

type PrivateKey struct {
	*PublicKey
	D *big.Int
}

PrivateKey is a P-521 elliptic curve private key implementation with a nested PublicKey.

func GenerateKey

func GenerateKey() (*PrivateKey, error)

GenerateKey generates a P-521 key pair.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

_ = privateKey.PublicKey // encapsulated public key
Output:

func ParsePrivateKey

func ParsePrivateKey(data []byte) *PrivateKey

ParsePrivateKey parses a P-521 private key from a byte slice.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// it's a good idea to encrypt this before saving it.
bytes := privateKey.Bytes() // exported private key bytes

privateKey = ParsePrivateKey(bytes) // same key as before
Output:

func (*PrivateKey) Bytes

func (sk *PrivateKey) Bytes() []byte

Bytes returns the bytes for the D value of this key.

The length of the returned slice will be PrivateKeyLength.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// it's a good idea to encrypt this before saving it.
bytes := privateKey.Bytes()

saveFile("myKey.sec", bytes)
Output:

func (*PrivateKey) DeriveKey

func (sk *PrivateKey) DeriveKey(pk *PublicKey) ([]byte, error)

DeriveKey passes the result of ECDH through a KDF.

The returned key can be safely used as an encryption key.

Example
// PrivateKey.DeriveKey(*PublicKey) is the same as PublicKey.DeriveKey(*PrivateKey)

// this is your key.
privateKey1, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// this key belongs to someone else.
privateKey2, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// the other person will send you their public key,
// which you can use to derive the shared key.
sharedKey1, err := privateKey1.DeriveKey(privateKey2.PublicKey)
if err != nil {
	log.Fatal(err)
}

// likewise, you will send your public key to the other
// person, and they'll use it to derive the shared key.
sharedKey2, err := privateKey2.DeriveKey(privateKey1.PublicKey)
if err != nil {
	log.Fatal(err)
}

// these keys are safe to use directly for encryption,
// unlike the shared secret returned from ECDH, because
// the library passes the shared ECDH secret through a
// secure key derivation function (KDF) to make this key.

// these shared keys will be the same.
fmt.Println(bytes.Equal(sharedKey1, sharedKey2)) // true
Output:

func (*PrivateKey) ECDH

func (sk *PrivateKey) ECDH(pk *PublicKey) []byte

ECDH calculates the shared key for this key and the provided public key.

Use DeriveKey if this shared secret will be used as an encryption key.

Example
// PrivateKey.ECDH(*PublicKey) is the same as PublicKey.ECDH(*PrivateKey)

// this is your key.
privateKey1, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// this key belongs to someone else.
privateKey2, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

// the other person will send you their public key, which
// you can use to derive the shared secret using ECDH.
sharedSecret1 := privateKey1.ECDH(privateKey2.PublicKey)

// likewise, you will send your public key to the other
// person, and they'll use it to derive the shared secret.
sharedSecret2 := privateKey2.ECDH(privateKey1.PublicKey)

// important note: you shouldn't use this shared secret
// directly as an encryption key. you should first pass
// it through a secure key derivation function (KDF).

// this library does this for you if you call the DeriveKey
// method in place of ECDH. the shared key is passed through
// a secure KDF, returning a key safe to use for encryption.

// these shared secrets will be the same.
fmt.Println(bytes.Equal(sharedSecret1, sharedSecret2)) // true
Output:

func (*PrivateKey) Equals

func (sk *PrivateKey) Equals(privKey *PrivateKey) bool

Equals returns whether the two private keys are identical.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}

bytes := privateKey.Bytes()      // encrypt and store
parsed := ParsePrivateKey(bytes) // decrypt and parse

fmt.Println(parsed.Equals(privateKey)) // true
Output:

type PublicKey

type PublicKey struct {
	X, Y *big.Int
}

PublicKey is a P-521 elliptic curve public key implementation.

func ParsePublicKey

func ParsePublicKey(data []byte) (*PublicKey, error)

ParsePublicKey parses a public key from a byte slice.

Both compressed and uncompressed keys are supported.

See elliptic.Marshal and elliptic.MarshalCompressed.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey := privateKey.PublicKey

// see PublicKey.Bytes() for more information.
bytes := publicKey.Bytes(true)

publicKey, err = ParsePublicKey(bytes) // same key as before
if err != nil {
	log.Fatal(err)
}
Output:

func (*PublicKey) Bytes

func (pk *PublicKey) Bytes(compressed bool) []byte

Bytes marshals this key and returns the associated bytes.

The length of the returned slice will be PublicKeyLengthCompressed if true is passed, or PublicKeyLengthUncompressed if false is passed.

See elliptic.Marshal and elliptic.MarshalCompressed.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey := privateKey.PublicKey

// pass true to compress the public key when marshalling.
// see ecies.PublicKeyLengthCompressed
// and ecies.PublicKeyLengthUncompressed
bytes := publicKey.Bytes(true)

saveFile("myKey.pub", bytes)
Output:

func (*PublicKey) DeriveKey

func (pk *PublicKey) DeriveKey(sk *PrivateKey) ([]byte, error)

DeriveKey passes the result of ECDH through a KDF.

The returned key can be safely used as an encryption key.

Example
// PublicKey.DeriveKey(*PrivateKey) is the same as PrivateKey.DeriveKey(*PublicKey)

// this is your key.
privateKey1, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey1 := privateKey1.PublicKey

// this key belongs to someone else.
privateKey2, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey2 := privateKey2.PublicKey

// the other person will send you their public key,
// which you can use to derive the shared key.
sharedKey1, err := publicKey1.DeriveKey(privateKey2)
if err != nil {
	log.Fatal(err)
}

// likewise, you will send your public key to the other
// person, and they'll use it to derive the shared key.
sharedKey2, err := publicKey2.DeriveKey(privateKey1)
if err != nil {
	log.Fatal(err)
}

// these keys are safe to use directly for encryption,
// unlike the shared secret returned from ECDH, because
// the library passes the shared ECDH secret through a
// secure key derivation function (KDF) to make this key.

// these shared keys will be the same.
fmt.Println(bytes.Equal(sharedKey1, sharedKey2)) // true
Output:

func (*PublicKey) ECDH

func (pk *PublicKey) ECDH(sk *PrivateKey) []byte

ECDH calculates the shared key for this key and the provided private key.

Use DeriveKey if this shared secret will be used as an encryption key.

Example
// PublicKey.ECDH(*PrivateKey) is the same as PrivateKey.ECDH(*PublicKey)

// this is your key.
privateKey1, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey1 := privateKey1.PublicKey

// this key belongs to someone else.
privateKey2, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey2 := privateKey2.PublicKey

// the other person will send you their public key, which
// you can use to derive the shared secret using ECDH.
sharedSecret1 := publicKey1.ECDH(privateKey2)

// likewise, you will send your public key to the other
// person, and they'll use it to derive the shared secret.
sharedSecret2 := publicKey2.ECDH(privateKey1)

// important note: you shouldn't use this shared secret
// directly as an encryption key. you should first pass
// it through a secure key derivation function (KDF).

// this library does this for you if you call the DeriveKey
// method in place of ECDH. the shared key is passed through
// a secure KDF, returning a key safe to use for encryption.

// these shared secrets will be the same.
fmt.Println(bytes.Equal(sharedSecret1, sharedSecret2)) // true
Output:

func (*PublicKey) Equals

func (pk *PublicKey) Equals(pubKey *PublicKey) bool

Equals returns whether the two public keys are identical.

Example
privateKey, err := GenerateKey()
if err != nil {
	log.Fatal(err)
}
publicKey := privateKey.PublicKey

// see PublicKey.Bytes() for more information.
bytes := publicKey.Bytes(true)       // encrypt and store
parsed, err := ParsePublicKey(bytes) // decrypt and parse
if err != nil {
	log.Fatal(err)
}

fmt.Println(parsed.Equals(publicKey)) // true
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL