aboutsummaryrefslogtreecommitdiff
path: root/ecdsa.go
blob: 8bf432d85fa97b7c5cba0171a9fe79ccdf069732 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package pki

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"encoding/asn1"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
)

// This label is used as the type in the pem encoding of ECDSA private keys.
const PemLabelEcdsa = "EC PRIVATE KEY"

type (
	// This type handles the function calls to the ecdsa private key by
	// implementing the interface.
	EcdsaPrivateKey struct {
		private_key *ecdsa.PrivateKey
	}

	// EcdsaPublicKey is the specific public key type for ecdsa. It implements the
	// the PublicKey interface.
	EcdsaPublicKey struct {
		public_key *ecdsa.PublicKey
	}

	// This struct is used to marshal and parse the ecdsa signature.
	signatureEcdsa struct {
		R, S *big.Int
	}
)

// Create a new ECDSA private key using the specified curve.
// For available curves, please take a look at the crypto/elliptic package.
func NewPrivateKeyEcdsa(curve elliptic.Curve) (*EcdsaPrivateKey, error) {
	key, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil, err
	}
	return &EcdsaPrivateKey{key}, nil
}

// Load the private key from the asn1 representation.
func LoadPrivateKeyEcdsa(raw []byte) (*EcdsaPrivateKey, error) {
	key, err := x509.ParseECPrivateKey(raw)
	if err != nil {
		return nil, err
	}
	return &EcdsaPrivateKey{key}, nil
}

// Create a new public key from the private key.
func (pr EcdsaPrivateKey) Public() PublicKey {
	return &EcdsaPublicKey{pr.private_key.Public().(*ecdsa.PublicKey)}
}

// Sign a message using the private key and the provided hash function.
func (pr EcdsaPrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) {
	empty := make([]byte, 0)
	if !hash.Available() {
		return empty, errors.New("Hash method is not available!")
	}
	hashed_message := hash.New()
	hashed_message.Write(message)
	return pr.private_key.Sign(rand.Reader, hashed_message.Sum(nil), hash)
}

// This function returns the crypto.PrivateKey structure of the ECDSA key.
func (pr EcdsaPrivateKey) PrivateKey() crypto.PrivateKey {
	return pr.private_key
}

// This function implements the Pemmer interface to marshal the private key
// into a pem block.
func (pr EcdsaPrivateKey) MarshalPem() (io.WriterTo, error) {
	pem_block, err := pr.ToPem()
	if err != nil {
		return nil, err
	}
	return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
}

// This function implements ToPem to return the raw pem block.
func (pr EcdsaPrivateKey) ToPem() (pem.Block, error) {
	asn1, err := x509.MarshalECPrivateKey(pr.private_key)
	if err != nil {
		return pem.Block{}, err
	}
	return pem.Block{Type: PemLabelEcdsa, Bytes: asn1}, nil
}

// This functoin loads an ecdsa public key from the asn.1 representation.
func LoadPublicKeyEcdsa(raw []byte) (*EcdsaPublicKey, error) {
	raw_pub, err := x509.ParsePKIXPublicKey(raw)
	if err != nil {
		return nil, err
	}

	pub, ok := raw_pub.(*ecdsa.PublicKey)
	if !ok {
		return nil, errors.New("Not an ecdsa key!")
	}
	return &EcdsaPublicKey{pub}, nil
}

// This function implements the Pemmer interface to marshal the public key into
// a pem block.
func (pu *EcdsaPublicKey) MarshalPem() (io.WriterTo, error) {
	asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
	if err != nil {
		return nil, err
	}
	pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1}
	return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
}

// This function verifies a message using the public key, signature and hash
// function.
// The hash function must be the same as was used to create the signature.
func (pu *EcdsaPublicKey) Verify(message []byte, signature_raw []byte, hash crypto.Hash) (bool, error) {
	var sig signatureEcdsa
	_, err := asn1.Unmarshal(signature_raw, &sig)
	if err != nil {
		return false, err
	}
	hashed_message := hash.New()
	hashed_message.Write(message)
	return ecdsa.Verify(pu.public_key, hashed_message.Sum(nil), sig.R, sig.S), nil
}