ecc

package module
v0.0.0-...-d86af7b Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2019 License: BSD-3-Clause Imports: 12 Imported by: 1

README

ecc elliptic curve cryptography

Go Report Card Documentation Coverage Status Build Status

Package ecc makes public key elliptic curve cryptography easier to use. Cryptographic functions are from "crypto/ecdsa" and "github.com/cloudflare/redoctober/ecdh".

Sign/Verify                // authentication by signing a hash
SignMessage/VerifyMessage  // authentication by hashing a message and signing the hash SHA256
Encrypt/Decrypt            // encrypts with ephemeral symetrical key AES-128-CBC-HMAC-SHA1
Seal/Open                  // both Sign and Encrypt, then Decrypt and Verify

Marshal/Unmarshal          // convert keys to and from []byte slices
PEM/DecodePEM              // keys in PEM file format, can be encrypted with a password

Packages ecdh, padding and symcrypt are copied from redoctober into this package so it works with go get. Only a few minor changes were made: package import paths, an error check and a comment added. Run ./diff_redoctober.sh to see all changes.

Documentation and Examples

Status

Status Documentation Examples Tests
Package alpha/stable X X X
eccutil alpha/stable X X
libecc alpha driver.c

eccutil

There is a command line utility in "cmd/eccutil". Usage and Examples

go install gitlab.com/elktree/ecc/cmd/eccutil

libecc

libecc is a C wrapper for package ecc.

go build -buildmode=c-shared

The windows directory has a batch file for building: libecc.def, libecc.lib and libecc.dll. There is also a test file driver.c

If you're on linux try setting the library path: LD_LIBRARY_PATH=. ./a.out

Build with Go 1.11.5 or 1.10.8 (or later)

This DoS vulnerability in the crypto/elliptic implementations of the P-521 and P-384 elliptic curves may let an attacker craft inputs that consume excessive amounts of CPU.

Message in a bottle

Photo by Guilherme Stecanella on Unsplash

Documentation

Overview

Package ecc makes public key elliptic curve cryptography easier to use. Cryptographic functions are from "crypto/ecdsa" and "github.com/cloudflare/redoctober/ecdh".

Sign/Verify                // authentication by signing a hash
SignMessage/VerifyMessage  // authentication by hashing a message and signing the hash SHA256
Encrypt/Decrypt            // encrypts with ephemeral symmetrical key AES-128-CBC-HMAC-SHA1
Seal/Open                  // both Sign and Encrypt, then Decrypt and Verify

Marshal/Unmarshal          // convert keys to and from []byte slices
PEM/DecodePEM              // keys in PEM file format, can be encrypted with a password

Packages ecdh, padding and symcrypt are copied from redoctober into this package so it works with go get. Only a few minor changes were made: package import paths, an error check and a comment added. Run ./diff_redoctober.sh to see all changes.

Example (Encrypt)
package main

import (
	"crypto/elliptic"
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	// create keys
	pub, priv, _ := ecc.GenerateKeys(elliptic.P521())

	plaintext := "secret secrets are no fun, secret secrets hurt someone"

	// use public key to encrypt
	encrypted, _ := pub.Encrypt([]byte(plaintext))
	fmt.Println(len(encrypted))

	// use private key to decrypt
	decrypted, _ := priv.Decrypt(encrypted)
	fmt.Println(string(decrypted))

}
Output:

234
secret secrets are no fun, secret secrets hurt someone
Example (EncyptedPEM)
package main

import (
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	const encryptedPem = `
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,94853fd16a027c0c07663ffc09cc32e6

cclqDp6HTJD/xB/nk3fDBDJLnSohMLnsjasx4l8QaD0hMICg/r4gtPHuzDHwxLGA
GHNahxeZkDYq/RutOjcihihC5FKdJJZ1b88EnXoprG7Kp2iwbPteD6mbzWqxwpbJ
aP0xnZAk+xghjHb9v/qxG2lFho/JpGIek8SfDLX5eH0=
-----END EC PRIVATE KEY-----
`

	// load private key with password "abc123"
	priv, _ := ecc.DecodePEMPrivateKey([]byte(encryptedPem), "abc123")

	// get PEM without encryption; password is blank
	plainPem, _ := priv.PEM("")
	fmt.Println(string(plainPem))

}
Output:

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFtZ6cvIvTN2yGlL/VDL0hfQCrui+wEg5/kt6X1KgfiBoAoGCCqGSM49
AwEHoUQDQgAE9rgmY7NQAqt4r3o2Bt4ViS8HWlHHJ+Ig2VIpRaxUyMrrZma9hHu5
SvdpYhDA1fClYKw0ZEKkuZ5xZFtCJ4/MkQ==
-----END EC PRIVATE KEY-----
Example (Marshal)
package main

import (
	"crypto/elliptic"
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	const privPem = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFtZ6cvIvTN2yGlL/VDL0hfQCrui+wEg5/kt6X1KgfiBoAoGCCqGSM49
AwEHoUQDQgAE9rgmY7NQAqt4r3o2Bt4ViS8HWlHHJ+Ig2VIpRaxUyMrrZma9hHu5
SvdpYhDA1fClYKw0ZEKkuZ5xZFtCJ4/MkQ==
-----END EC PRIVATE KEY-----
`
	// load keys (the private key contains the public key)
	priv, _ := ecc.DecodePEMPrivateKey([]byte(privPem), "")

	// ecc.Keys are wrappers around ecdsa.Keys
	pub := ecc.PublicKey{Key: &priv.Key.PublicKey}

	// A single byte (x04) is prefixed to the raw public key bytes when marshalled,
	// indicating that the key is uncompressed. This makes a P-256 public key 65
	// bytes instead of 32 bytes for X and 32 bytes for Y.
	pubMarshalled := pub.Marshal()
	fmt.Printf("public key len(%d): %x...\n", len(pubMarshalled), pubMarshalled[:20])

	// Marshaled private key (in x509 ASN.1, DER format) is 121 bytes. It stores
	// the 32 bytes of private key, 65 bytes of public key, the curve ID and a
	// version number.
	privMarshalled, _ := priv.Marshal()
	fmt.Printf("private key len(%d): %x...\n", len(privMarshalled), privMarshalled[:20])

	priv2, _ := ecc.UnmarshalPrivateKey(privMarshalled)
	fmt.Println(priv2.Key.Params().Name)

	pub2 := ecc.UnmarshalPublicKey(elliptic.P256(), pubMarshalled)
	fmt.Println(&pub == pub2) // false. same values but not the same pointers

}
Output:

public key len(65): 04f6b82663b35002ab78af7a3606de15892f075a...
private key len(121): 307702010104205b59e9cbc8bd3376c8694bfd50...
P-256
false
Example (PEM)
package main

import (
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	const privPem = `
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAED2R9NFkyj4E5ITbx20iSiYyHVxvxl7awC1aPfZ49KunnssO97+07
R7qyhIUZ6aCgBwYFK4EEACKhZANiAAShYa1f7DltZ2tDBHs6MdgMt3MV8u0DOIC+
ZZ3LjvP5corPnvkXgJI/0np63Zm09KsEbK/JB/tL6Lzp30ROxRbmOuxGSbL353jD
zaXKbGmizJi2+Vr/0BQKXEM0h2laHDU=
-----END EC PRIVATE KEY-----
`
	// load keys (the private key contains the public key)
	priv, _ := ecc.DecodePEMPrivateKey([]byte(privPem), "")

	// ecc.Keys are wrappers around ecdsa.Keys
	pub := ecc.PublicKey{Key: &priv.Key.PublicKey}

	// get public key in PEM format
	pubPem, _ := pub.PEM()
	fmt.Println(string(pubPem))

}
Output:

-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEoWGtX+w5bWdrQwR7OjHYDLdzFfLtAziA
vmWdy47z+XKKz575F4CSP9J6et2ZtPSrBGyvyQf7S+i86d9ETsUW5jrsRkmy9+d4
w82lymxposyYtvla/9AUClxDNIdpWhw1
-----END PUBLIC KEY-----
Example (SealOpen)
package main

import (
	"bytes"
	"crypto/elliptic"
	"crypto/rand"
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	// create keys, NB: different curves are used for sender and receiver
	sendersPub, sendersPriv, _ := ecc.GenerateKeys(elliptic.P224())
	receiversPub, receiversPriv, _ := ecc.GenerateKeys(elliptic.P521())

	// get random bytes as plaintext
	plaintextBytes := make([]byte, 8192)
	if n, err := rand.Reader.Read(plaintextBytes); n != 8192 || err != nil {
		panic("failed to read random bytes")
	}

	// seal both signs and encrypts
	sealed, _ := sendersPriv.Seal(plaintextBytes, receiversPub)

	// send the sealed bytes

	// open decrypts and verifies the senders signature
	opened, _ := receiversPriv.Open(sealed, sendersPub)

	compared := bytes.Compare(plaintextBytes, opened)
	fmt.Println(compared == 0)

}
Output:

true
Example (SignMessage)
package main

import (
	"crypto/elliptic"
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	// create keys
	pub, priv, _ := ecc.GenerateKeys(elliptic.P384())

	plaintext := "secret secrets are no fun, secret secrets hurt someone"

	// Sign the message with the senders private key.
	sig, _ := priv.SignMessage([]byte(plaintext))

	// send plaintext and sig

	// Verify the signature with the senders public key.
	verified, _ := pub.VerifyMessage([]byte(plaintext), sig)
	fmt.Println(verified)

}
Output:

true
Example (SignVerify)
package main

import (
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"fmt"

	"gitlab.com/elktree/ecc"
)

func main() {
	// create keys
	pub, priv, _ := ecc.GenerateKeys(elliptic.P224())

	// get random bytes as plaintext
	plaintextBytes := make([]byte, 2500)
	if n, err := rand.Reader.Read(plaintextBytes); n != 2500 || err != nil {
		panic("failed to read random bytes")
	}
	hash := sha256.Sum256(plaintextBytes)

	// Sign the hash with the senders private key.
	sig, _ := priv.Sign(hash[:]) // hash is type [32]byte, need []byte

	// send plaintext and sig

	// Verify the signature with the senders public key. The recipient should
	// create the hash from the plaintext (here we reuse the hash).
	verified, _ := pub.Verify(hash[:], sig)
	fmt.Println(verified)

}
Output:

true

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateKeys

func GenerateKeys(curve elliptic.Curve) (pub *PublicKey, priv *PrivateKey, err error)

GenerateKeys creates a new public and private key pair. Note that the public key is double the size of the private key. Using elliptic.P256() would make the private key 32 bytes and the public key 64 bytes.

pub, priv, err := ecc.GenerateKeys(elliptic.P256())

Types

type PrivateKey

type PrivateKey struct {
	Key *ecdsa.PrivateKey
}

PrivateKey is the elliptic private key.

func DecodePEMPrivateKey

func DecodePEMPrivateKey(pemEncodedKey []byte, password string) (*PrivateKey, error)

DecodePEMPrivateKey decodes the PEM format for the elliptic PrivateKey. If password is not blank, the PEM will be decrypted first.

pem.Decode will find the next PEM formatted block (certificate, private key etc) in the input. It returns that block and the remainder of the input. If no PEM data is found, p is nil and the whole of the input is returned in rest.

x509.DecryptPEMBlock takes a password encrypted PEM block and the password used to encrypt it and returns a slice of decrypted DER encoded bytes. It inspects the DEK-Info header to determine the algorithm used for decryption. If no DEK-Info header is present, an error is returned. If an incorrect password is detected an IncorrectPasswordError is returned. Because of deficiencies in the encrypted-PEM format, it's not always possible to detect an incorrect password. In these cases no error will be returned but the decrypted DER bytes will be random noise.

func UnmarshalPrivateKey

func UnmarshalPrivateKey(marshalledKey []byte) (*PrivateKey, error)

UnmarshalPrivateKey loads a PrivateKey from a marshalled byte slice.

x509.ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.

func (*PrivateKey) Decrypt

func (priv *PrivateKey) Decrypt(encrypted []byte) (message []byte, err error)

Decrypt authenticates and recovers the original message from its input using the private key and the ephemeral key included in the message.

func (*PrivateKey) Marshal

func (priv *PrivateKey) Marshal() ([]byte, error)

Marshal converts a PrivateKey to a byte slice.

MarshalECPrivateKey marshals an EC private key into ASN.1, DER format.

func (*PrivateKey) Open

func (priv *PrivateKey) Open(sealed []byte, from *PublicKey) ([]byte, error)

Open decrypts and authenticates by calling Decrypt() and VerifyMessage(). Open is used after Seal().

func (*PrivateKey) PEM

func (priv *PrivateKey) PEM(password string) ([]byte, error)

PEM marshals the PrivateKey and encodes it in standard PEM format. If password is not blank, the PEM will be encrypted using x509.PEMCipherAES256.

x509.MarshalECPrivateKey marshals an EC private key into ASN.1, DER format.

x509.EncryptPEMBlock returns a PEM block of the specified type holding the given DER-encoded data encrypted with the specified algorithm and password.

func (*PrivateKey) Seal

func (priv *PrivateKey) Seal(message []byte, to *PublicKey) (sealed []byte, err error)

Seal authenticates and encrypts by calling SignMessage() and Encrypt(). Use Open() after Seal.

func (*PrivateKey) Sign

func (priv *PrivateKey) Sign(hash []byte) (signature []byte, err error)

Sign uses the PrivateKey to create a signature of a hash (which should be the result of hashing a larger message.) Use Verify() after Sign.

If the hash is longer than the bit-length of the private key's curve order, the hash will be truncated to that length.

func (*PrivateKey) SignMessage

func (priv *PrivateKey) SignMessage(message []byte) (signature []byte, err error)

SignMessage will hash the message with Sha256 and sign the hash. Returns a signature and error. Use VerifyMessage() after SignMessage.

type PublicKey

type PublicKey struct {
	Key *ecdsa.PublicKey
}

PublicKey is the elliptic public key.

func DecodePEMPublicKey

func DecodePEMPublicKey(pemEncodedKey []byte) (*PublicKey, error)

DecodePEMPublicKey decodes the PEM format for the elliptic PublicKey.

pem.Decode will find the next PEM formatted block (certificate, private key etc) in the input. It returns that block and the remainder of the input. If no PEM data is found, p is nil and the whole of the input is returned in rest.

func UnmarshalPublicKey

func UnmarshalPublicKey(curve elliptic.Curve, marshalledKey []byte) *PublicKey

UnmarshalPublicKey loads a PublicKey from a marshalled byte slice.

elliptic.Unmarshal converts a point, serialized by Marshal, into an x, y pair. It is an error if the point is not in uncompressed form or is not on the curve. On error, x = nil.

func (*PublicKey) Encrypt

func (pub *PublicKey) Encrypt(message []byte) (encrypted []byte, err error)

Encrypt secures and authenticates its input with the public key, using ECDHE with AES-128-CBC-HMAC-SHA1.

func (*PublicKey) Marshal

func (pub *PublicKey) Marshal() []byte

Marshal converts the PublicKey to a byte slice.

elliptic.Marshal converts a point into the uncompressed form specified in section 4.3.6 of ANSI X9.62.

func (*PublicKey) PEM

func (pub *PublicKey) PEM() ([]byte, error)

PEM marshals the PublicKey and encodes it in standard PEM format.

x509.MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.

func (*PublicKey) Verify

func (pub *PublicKey) Verify(hash, signature []byte) (bool, error)

Verify checks the signature was created by the PrivateKey that goes with this PublicKey. Returns true if valid.

Signatures are created by the sender calling PrivateKey.Sign(hash) where the hash is of a larger message. The recipient uses the senders public key to check the senders signature. The recipient must hash the larger message (with the same algorithm) and verify the hash with the signature.

func (*PublicKey) VerifyMessage

func (pub *PublicKey) VerifyMessage(message, signature []byte) (verified bool, err error)

VerifyMessage will hash the message with Sha256, and then verify the signature.

Directories

Path Synopsis
cmd
eccutil
Command eccutil is for working with elliptic curves.
Command eccutil is for working with elliptic curves.
Package ecdh encrypts and decrypts data using elliptic curve keys.
Package ecdh encrypts and decrypts data using elliptic curve keys.
libecc is a C wrapper for package ecc.
libecc is a C wrapper for package ecc.
Package padding adds and removes padding for AES-CBC mode.
Package padding adds and removes padding for AES-CBC mode.
Package symcrypt contains common symmetric encryption functions.
Package symcrypt contains common symmetric encryption functions.

Jump to

Keyboard shortcuts

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