easyecc

package module
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2023 License: MIT Imports: 23 Imported by: 17

README

Easy Elliptic Curve Cryptography in Go

GitHub Workflow Status GoDoc reference example GoReportCard example Coverage Status

This package ties several other commonly used cryptography packages together. The goal is to make common cryptographic operations simple. The following elliptic curves are supported:

This package was originally the part of https://github.com/regnull/ubikom, but then became its own little package, because why not.

Examples

(see examples_test.go and encryption_test.go files).

Elliptic curves are defined as constants:

const (
	SECP256K1 EllipticCurve = 1
	P256      EllipticCurve = 2
	P384      EllipticCurve = 3
	P521      EllipticCurve = 4
)

Use them when creating keys.

Sign hash and verify signature (Using ECDSA)

privateKey := CreatePrivateKey(P256, big.NewInt(12345))
data := "super secret message"
hash := Hash256([]byte(data))
signature, err := privateKey.Sign(hash)
if err != nil {
	log.Fatal(err)
}
publicKey := privateKey.PublicKey()
success := signature.Verify(publicKey, hash)
fmt.Printf("Signature verified: %v\n", success)
// Output: Signature verified: true

Encrypt with shared secret (Using ECDH):

aliceKey, err := GeneratePrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
bobKey, err := GeneratePrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
data := "super secret message"
encrypted, err := aliceKey.EncryptECDH([]byte(data), bobKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
decrypted, err := bobKey.DecryptECDH(encrypted, aliceKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s\n", string(decrypted))
// Output: super secret message

Encrypt private key with passphrase

privateKey := CreatePrivateKey(P256, big.NewInt(12345))
encryptedKey, err := privateKey.EncryptKeyWithPassphrase("my passphrase")
if err != nil {
	log.Fatal(err)
}
decryptedKey, err := CreatePrivateKeyFromEncrypted(P256, encryptedKey, "my passphrase")
fmt.Printf("%d\n", decryptedKey.Secret())
// Output: 12345

Serialize Public Key

privateKey := CreatePrivateKey(P256, big.NewInt(12345))
publicKey := privateKey.PublicKey()
serializedCompressed := publicKey.SerializeCompressed()
fmt.Printf("%x\n", serializedCompressed)
publicKeyCopy, err := DeserializeCompressed(P256, serializedCompressed)
if err != nil {
	log.Fatal(err)
}
sameKey := publicKey.Equal(publicKeyCopy)
fmt.Printf("the correct key was created: %v\n", sameKey)
// Output: 0226efcebd0ee9e34a669187e18b3a9122b2f733945b649cc9f9f921e9f9dad812
// the correct key was created: true

Getting Bitcoin and Ethereum addresses:

// BitcoinAddress and EthereumAddress only work for secp256k1 curve.
privateKey := CreatePrivateKey(SECP256K1, big.NewInt(12345))
publicKey := privateKey.PublicKey()
bitcoinAddress, err := publicKey.BitcoinAddress()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Bitcoin address: %s\n", bitcoinAddress)
ethereumAddress, err := publicKey.EthereumAddress()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Ethereum address: %s\n", ethereumAddress)
// Output: Bitcoin address: 12vieiAHxBe4qCUrwvfb2kRkDuc8kQ2VZ2
// Ethereum address: 0xEB4665750b1382DF4AeBF49E04B429AAAc4d9929

JWK Support

EasyECC offers some limited JWK support (see https://www.rfc-editor.org/rfc/rfc7517). Private keys can be exported and imported as JWK JSON:

privateKey := CreatePrivateKey(P256, big.NewInt(12345))
jwkBytes, err := privateKey.MarshalToJWK()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s\n", jwkBytes)

privateKeyCopy, err := CreatePrivateKeyFromJWK(jwkBytes)
if err != nil {
	log.Fatal(err)
}
if privateKey.Equal(privateKeyCopy) {
	fmt.Printf("keys match!")
}
// Output: {
//   "kty": "EC",
//   "crv": "P-256",
//   "x": "Ju/OvQ7p40pmkYfhizqRIrL3M5RbZJzJ+fkh6fna2BI",
//   "y": "kCOL3pzHuzMNFQxncE3SWucFUgV0S28xv0BwdFhy0OY",
//   "d": "MDk"
// }
// keys match!

Documentation

Overview

Package easyecc ties together several other common packages and makes it easy to perform common elliptic key cryptography operations on multiple curves (including secp256k1, used by Bitcoin, see https://en.bitcoin.it/wiki/Secp256k1).

In addition to secp256k1, P-256, P-384 and P-521 are also supported.

These operations include:

-- Creating private keys, in various ways

-- Saving private key to file, possibly passphrase-protected

-- Reading and decrypting private key from file

-- Signing data using the private key and verifying with the public key (ECDSA)

-- Encrypting data using a symmetric encryption key derived from private key/public key pair (ECDH)

See the examples for more information.

Index

Examples

Constants

View Source
const (
	PBKDF2_ITER = 16384
	PBKDF2_SIZE = 32
)

Variables

View Source
var ErrDifferentCurves = fmt.Errorf("the keys must use the same curve")
View Source
var ErrUnsupportedCurve = fmt.Errorf("the operation is not supported on this curve")
View Source
var ErrUnsupportedKeyType = fmt.Errorf("unsupported key type")

Functions

func Hash160

func Hash160(buf []byte) []byte

Hash160 calculates the hash ripemd160(sha256(b)).

func Hash256

func Hash256(data []byte) []byte

Hash256 does two rounds of SHA256 hashing.

Types

type EllipticCurve added in v1.0.0

type EllipticCurve int
const (
	INVALID_CURVE EllipticCurve = -1
	SECP256K1     EllipticCurve = 1
	P256          EllipticCurve = 2
	P384          EllipticCurve = 3
	P521          EllipticCurve = 4
)

func StringToEllipticCurve added in v1.0.3

func StringToEllipticCurve(s string) EllipticCurve

func (EllipticCurve) String added in v1.0.3

func (ec EllipticCurve) String() string

type PrivateKey

type PrivateKey struct {
	// contains filtered or unexported fields
}

PrivateKey represents elliptic cryptography private key.

func CreatePrivateKey added in v1.0.0

func CreatePrivateKey(curve EllipticCurve, secret *big.Int) *PrivateKey

CreatePrivateKey creates a private key on the given curve from secret.

func CreatePrivateKeyFromEncrypted added in v1.0.0

func CreatePrivateKeyFromEncrypted(curve EllipticCurve, data []byte, passphrase string) (*PrivateKey,
	error)

CreatePrivateKeyFromEncrypted creates a private key from from encrypted private key using the passphrase. Encryption is done using AES-256 with CGM cipher, with a key derived from the passphrase.

func CreatePrivateKeyFromFile added in v1.0.0

func CreatePrivateKeyFromFile(curve EllipticCurve, fileName string, passphrase string) (*PrivateKey, error)

NewPrivateKeyFromFile loads private key using given curve from file and decrypts it using the given passphrase. If the passphrase is an empty string, no decryption is done (the file content is assumed to be not encrypted).

func CreatePrivateKeyFromJWK added in v1.0.3

func CreatePrivateKeyFromJWK(data []byte) (*PrivateKey, error)

CreatePrivateKeyFromJWK creates private key from JWK-encoded representation. See https://www.rfc-editor.org/rfc/rfc7517.

func CreatePrivateKeyFromJWKFile added in v1.0.3

func CreatePrivateKeyFromJWKFile(fileName string, passphrase string) (*PrivateKey, error)

CreatePrivateKeyFromJWKFile loads private key from file in JWK format, optionally decrypting it.

func CreatePrivateKeyFromMnemonic added in v1.0.0

func CreatePrivateKeyFromMnemonic(curve EllipticCurve, mnemonic string) (*PrivateKey, error)

NewPrivateKeyFromMnemonic creates private key on given curve from a mnemonic phrase.

func CreatePrivateKeyFromPassword added in v1.0.0

func CreatePrivateKeyFromPassword(curve EllipticCurve, password, salt []byte) *PrivateKey

CreatePrivateKeyFromPassword creates a private key on the given curve from password using PBKDF2 algorithm.

func GeneratePrivateKey added in v1.0.0

func GeneratePrivateKey(curve EllipticCurve) (*PrivateKey, error)

GeneratePrivateKey creates a new random private key, given a curve.

func NewPrivateKey deprecated

func NewPrivateKey(secret *big.Int) *PrivateKey

NewPrivateKey returns new private key created from the secret using SECP256K1 curve.

Deprecated: Use CreatePrivateKey instead.

func NewPrivateKeyFromEncryptedWithPassphrase deprecated

func NewPrivateKeyFromEncryptedWithPassphrase(data []byte, passphrase string) (*PrivateKey, error)

NewPrivateKeyFromEncryptedWithPassphrase creates a new private key using SECP256K1 curve from encrypted private key using the passphrase.

Deprecated: Use CreatePrivateKeyFromEncrypted instead.

func NewPrivateKeyFromFile deprecated

func NewPrivateKeyFromFile(fileName string, passphrase string) (*PrivateKey, error)

NewPrivateKeyFromFile loads private key using SECP256K1 curve from file and decrypts it using the given passphrase. If the passphrase is an empty string, no decryption is done (the file content is assumed to be not encrypted).

Deprecated: Use CreatePrivateKeyFromFile instead.

func NewPrivateKeyFromMnemonic deprecated added in v0.1.3

func NewPrivateKeyFromMnemonic(mnemonic string) (*PrivateKey, error)

NewPrivateKeyFromMnemonic creates private key on SECP256K1 curve from a mnemonic phrase.

Deprecated: Use CreatePrivateKeyFromMnemonic instead.

func NewPrivateKeyFromPassword deprecated

func NewPrivateKeyFromPassword(password, salt []byte) *PrivateKey

NewPrivateKeyFromPassword creates a new private key from password and salt using SECP256K1 curve.

Deprecated: Use CreatePrivateKeyFromPassword.

func NewRandomPrivateKey deprecated

func NewRandomPrivateKey() (*PrivateKey, error)

NewRandomPrivateKey creates a new random private key using SECP256K1 curve.

Deprecated: Use GeneratePrivateKey instead.

func (*PrivateKey) Curve added in v1.0.0

func (pk *PrivateKey) Curve() EllipticCurve

Curve returns the elliptic curve for this public key.

func (*PrivateKey) Decrypt deprecated

func (pk *PrivateKey) Decrypt(content []byte, publicKey *PublicKey) ([]byte, error)

Decrypt decrypts content with a shared key derived from this private key and the counter party public key.

Deprecated: Use DecryptECDH instead, which works on all supported curves. Notice that Encrypt/Decrypt and EncryptECDH/DecryptECDH are not compatible on secp256k1 curve, since they are using different ways of generating shared encryption key.

func (*PrivateKey) DecryptECDH added in v1.0.0

func (pk *PrivateKey) DecryptECDH(content []byte, publicKey *PublicKey) ([]byte, error)

func (*PrivateKey) DecryptSymmetric added in v0.1.4

func (pk *PrivateKey) DecryptSymmetric(content []byte) ([]byte, error)

DecryptSymmetric decrypts the content that was previously encrypted using this private key. Decryption is done using AES-256 with CGM cipher.

func (*PrivateKey) Encrypt deprecated

func (pk *PrivateKey) Encrypt(content []byte, publicKey *PublicKey) ([]byte, error)

Encrypt encrypts content with a shared key derived from this private key and the counter party public key. Works only on secp256k1 curve.

Deprecated: Use EncryptECDH instead, which works on all supported curves. Notice that Encrypt/Decrypt and EncryptECDH/DecryptECDH are not compatible on secp256k1 curve, since they are using different ways of generating shared encryption key.

Example
aliceKey, err := GeneratePrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
bobKey, err := GeneratePrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
data := "super secret message"
encrypted, err := aliceKey.EncryptECDH([]byte(data), bobKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
decrypted, err := bobKey.DecryptECDH(encrypted, aliceKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s\n", string(decrypted))
Output:

super secret message

func (*PrivateKey) EncryptECDH added in v1.0.0

func (pk *PrivateKey) EncryptECDH(content []byte, publicKey *PublicKey) ([]byte, error)

func (*PrivateKey) EncryptKeyWithPassphrase

func (pk *PrivateKey) EncryptKeyWithPassphrase(passphrase string) ([]byte, error)

EncryptKeyWithPassphrase encrypts this private key using a passphrase. Encryption is done using AES-256 with CGM cipher, with a key derived from the passphrase.

Example
privateKey := CreatePrivateKey(P256, big.NewInt(12345))
encryptedKey, err := privateKey.EncryptKeyWithPassphrase("my passphrase")
if err != nil {
	log.Fatal(err)
}
decryptedKey, err := CreatePrivateKeyFromEncrypted(P256, encryptedKey, "my passphrase")
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%d\n", decryptedKey.Secret())
Output:

12345

func (*PrivateKey) EncryptSymmetric added in v0.1.4

func (pk *PrivateKey) EncryptSymmetric(content []byte) ([]byte, error)

EncryptSymmetric encrypts content using this private key. The same private key must be used for decryption. Encryption is done using AES-256 with CGM cipher.

func (*PrivateKey) Equal added in v0.1.3

func (pk *PrivateKey) Equal(other *PrivateKey) bool

Equal returns true if this key is equal to the other key.

func (*PrivateKey) GetECDHEncryptionKey added in v1.0.0

func (pk *PrivateKey) GetECDHEncryptionKey(publicKey *PublicKey) ([]byte, error)

GetECDHEncryptionKey returns a shared key that can be used to encrypt data exchanged by two parties, using Elliptic Curve Diffie-Hellman algorithm (ECDH). For Alice and Bob, the key is guaranteed to be the same when it's derived from Alice's private key and Bob's public key or Alice's public key and Bob's private key.

See https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman.

func (*PrivateKey) MarshalToJWK added in v1.0.3

func (pk *PrivateKey) MarshalToJWK() ([]byte, error)

MarshalToJWK returns the key JWK representation, see https://www.rfc-editor.org/rfc/rfc7517.

Example
privateKey := CreatePrivateKey(P256, big.NewInt(12345))
jwkBytes, err := privateKey.MarshalToJWK()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s\n", jwkBytes)

privateKeyCopy, err := CreatePrivateKeyFromJWK(jwkBytes)
if err != nil {
	log.Fatal(err)
}
if privateKey.Equal(privateKeyCopy) {
	fmt.Printf("keys match!")
}
Output:

{
  "kty": "EC",
  "crv": "P-256",
  "x": "Ju/OvQ7p40pmkYfhizqRIrL3M5RbZJzJ+fkh6fna2BI",
  "y": "kCOL3pzHuzMNFQxncE3SWucFUgV0S28xv0BwdFhy0OY",
  "d": "MDk"
}
keys match!

func (*PrivateKey) Mnemonic added in v0.1.3

func (pk *PrivateKey) Mnemonic() (string, error)

Mnemonic returns a mnemonic phrase which can be used to recover this private key.

func (*PrivateKey) PublicKey

func (pk *PrivateKey) PublicKey() *PublicKey

PublicKey returns the public key derived from this private key.

func (*PrivateKey) Save

func (pk *PrivateKey) Save(fileName string, passphrase string) error

Save saves the private key to the specified file. If the passphrase is given, the key will be encrypted with this passphrase. If the passphrase is an empty string, the key is not encrypted.

func (*PrivateKey) SaveAsJWK added in v1.0.3

func (pk *PrivateKey) SaveAsJWK(fileName string, passphrase string) error

SaveAsJWK writes the key to a file in JWK format, optionally encrypting it with a passphrase.

func (*PrivateKey) Secret

func (pk *PrivateKey) Secret() *big.Int

Secret returns the private key's secret.

func (*PrivateKey) Sign

func (pk *PrivateKey) Sign(hash []byte) (*Signature, error)

Sign signs (ECDSA) the hash using the private key and returns signature. See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm.

Example
privateKey := CreatePrivateKey(P256, big.NewInt(12345))
data := "super secret message"
hash := Hash256([]byte(data))
signature, err := privateKey.Sign(hash)
if err != nil {
	log.Fatal(err)
}
publicKey := privateKey.PublicKey()
success := signature.Verify(publicKey, hash)
fmt.Printf("Signature verified: %v\n", success)
Output:

Signature verified: true

func (*PrivateKey) ToECDSA added in v0.1.5

func (pk *PrivateKey) ToECDSA() *ecdsa.PrivateKey

ToECDSA returns this key as crypto/ecdsa private key.

type PublicKey

type PublicKey struct {
	// contains filtered or unexported fields
}

PublicKey represents elliptic curve cryptography private key.

func CreatePublicKeyFromPoint added in v1.0.4

func CreatePublicKeyFromPoint(curve elliptic.Curve, x *big.Int, y *big.Int) *PublicKey

CreatePublicKeyFromPoint creates a new public key given a point on the curve.

func Deserialize added in v1.0.0

func Deserialize(curve EllipticCurve, serialized []byte) (*PublicKey, error)

func DeserializeCompressed added in v1.0.0

func DeserializeCompressed(curve EllipticCurve, serialized []byte) (*PublicKey, error)

func NewPublicFromSerializedCompressed

func NewPublicFromSerializedCompressed(serialized []byte) (*PublicKey, error)

NewPublicFromSerializedCompressed creates new public key from serialized compressed format.

func (*PublicKey) BitcoinAddress added in v1.0.0

func (pbk *PublicKey) BitcoinAddress() (string, error)

BitcoinAddress returns the Bitcoin address for this public key. Unless the public key is on SECP256K1 curve, ErrUnsupportedCurve is returned.

func (*PublicKey) Curve added in v1.0.0

func (pbk *PublicKey) Curve() EllipticCurve

Curve returns the elliptic curve for this public key.

func (*PublicKey) Equal

func (pbk *PublicKey) Equal(other *PublicKey) bool

Equal returns true if this key is equal to the other key.

func (*PublicKey) EqualSerializedCompressed

func (pbk *PublicKey) EqualSerializedCompressed(other []byte) bool

EqualSerializedCompressed returns true if this key is equal to the other, given as serialized compressed representation.

func (*PublicKey) EthereumAddress added in v0.1.6

func (pbk *PublicKey) EthereumAddress() (string, error)

EthereumAddress returns an Ethereum address for this public key. Unless the public key is on SECP256K1 curve, ErrUnsupportedCurve is returned.

func (*PublicKey) Serialize added in v1.0.0

func (pbk *PublicKey) Serialize() []byte

func (*PublicKey) SerializeCompressed

func (pbk *PublicKey) SerializeCompressed() []byte

SerializeCompressed returns the private key serialized in SEC compressed format. The result is 33 bytes long.

Example
privateKey := CreatePrivateKey(P256, big.NewInt(12345))
publicKey := privateKey.PublicKey()
serializedCompressed := publicKey.SerializeCompressed()
fmt.Printf("%x\n", serializedCompressed)
publicKeyCopy, err := DeserializeCompressed(P256, serializedCompressed)
if err != nil {
	log.Fatal(err)
}
sameKey := publicKey.Equal(publicKeyCopy)
fmt.Printf("the correct key was created: %v\n", sameKey)
Output:

0226efcebd0ee9e34a669187e18b3a9122b2f733945b649cc9f9f921e9f9dad812
the correct key was created: true

func (*PublicKey) ToECDSA added in v0.1.5

func (pbk *PublicKey) ToECDSA() *ecdsa.PublicKey

ToECDSA returns this key as crypto/ecdsa public key.

func (*PublicKey) X

func (pbk *PublicKey) X() *big.Int

X returns X component of the public key.

func (*PublicKey) Y

func (pbk *PublicKey) Y() *big.Int

Y returns Y component of the public key.

type Signature

type Signature struct {
	R *big.Int
	S *big.Int
}

Signature represents a cryptographic signature (ECDSA). See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm

func (*Signature) Verify

func (sig *Signature) Verify(key *PublicKey, hash []byte) bool

Verify verifies the signer using the public key and the hash of the data.

Jump to

Keyboard shortcuts

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