easyecc

package module
v2.0.4-alpha Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2023 License: MIT Imports: 23 Imported by: 0

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 := NewPrivateKeyFromSecret(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 := NewPrivateKey(P256)
if err != nil {
    log.Fatal(err)
}
bobKey, err := NewPrivateKey(P256)
if err != nil {
    log.Fatal(err)
}
data := "super secret message"
encrypted, err := aliceKey.Encrypt([]byte(data), bobKey.PublicKey())
if err != nil {
    log.Fatal(err)
}
decrypted, err := bobKey.Decrypt(encrypted, aliceKey.PublicKey())
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s\n", string(decrypted))
// Output: super secret message

Serialize Public Key as JSON (Using JWK)

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

privateKeyCopy, err := NewPrivateKeyFromJSON(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!

Getting Bitcoin and Ethereum addresses:

// BitcoinAddress and EthereumAddress only work for secp256k1 curve.
privateKey := NewPrivateKeyFromSecret(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

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

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

func StringToEllipticCurve

func StringToEllipticCurve(s string) EllipticCurve

StringToEllipticCurve converts the elliptic curve name to EllipticCurve. If the name is not recognized, INVALID_CURVE is returned.

func (EllipticCurve) String

func (ec EllipticCurve) String() string

String returns the elliptic curve name as a string.

type PrivateKey

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

PrivateKey represents elliptic cryptography private key.

func NewPrivateKey

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

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

func NewPrivateKeyFromFile

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

NewPrivateKeyFromFile loads private key from fileName. If no passphrase is give, the file is assumed to be in JWK format. If passphrase is given, the file is assumed to be in JWE format, containing encrypted JWK key.

func NewPrivateKeyFromJSON

func NewPrivateKeyFromJSON(data string) (*PrivateKey, error)

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

func NewPrivateKeyFromMnemonic

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

NewPrivateKeyFromMnemonic creates private key on given curve from a mnemonic phrase. Only SECP256K1 and P256 keys can be created from mnemonic.

func NewPrivateKeyFromPassword

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

NewPrivateKeyFromPassword creates a private key on the given curve from password using PBKDF2 algorithm. See https://en.wikipedia.org/wiki/PBKDF2.

func NewPrivateKeyFromSecret

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

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

func (*PrivateKey) Curve

func (pk *PrivateKey) Curve() EllipticCurve

Curve returns the elliptic curve for this public key.

func (*PrivateKey) Decrypt

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

func (*PrivateKey) DecryptSymmetric

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

func (pk *PrivateKey) Encrypt(content []byte, publicKey *PublicKey) ([]byte, error)
Example
aliceKey, err := NewPrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
bobKey, err := NewPrivateKey(P256)
if err != nil {
	log.Fatal(err)
}
data := "super secret message"
encrypted, err := aliceKey.Encrypt([]byte(data), bobKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
decrypted, err := bobKey.Decrypt(encrypted, aliceKey.PublicKey())
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s\n", string(decrypted))
Output:

super secret message

func (*PrivateKey) EncryptSymmetric

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. TODO: Use JWE here? The function itself would probably go to deprecated package.

func (*PrivateKey) Equal

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

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

func (*PrivateKey) GetECDHEncryptionKey

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) MarshalToJSON

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

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

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

privateKeyCopy, err := NewPrivateKeyFromJSON(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

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 passphrase is empty, the file will contain the key in JWK format. Otherwise, the file will contain encrypted JWK key in JWE format.

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 := NewPrivateKeyFromSecret(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

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 NewPublicKeyFromBytes

func NewPublicKeyFromBytes(curve EllipticCurve, b []byte) (*PublicKey, error)

func NewPublicKeyFromCompressedBytes

func NewPublicKeyFromCompressedBytes(curve EllipticCurve, b []byte) (*PublicKey, error)

func NewPublicKeyFromPoint

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

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

func (*PublicKey) BitcoinAddress

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) Bytes

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

func (*PublicKey) CompressedBytes

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

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

func (*PublicKey) Curve

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

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) ToECDSA

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