-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathECDH.go
149 lines (126 loc) · 3.98 KB
/
ECDH.go
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Library code for Diffie-Hellman key generation and exchange. This code uses
// the NIST standard P-256 curve as well as SHA-256 for key derivation.
//
// SECURITY WARNING: This code is meant for educational purposes and may
// contain vulnerabilities or other bugs. Please do not use it for
// security-critical applications.
//
// GRADING NOTES: your code will be evaluated using this code. If you modify
// this code remember that the default version will be used for grading. You
// should add functions as needed in chatter.go or other supplemental files,
// not here.
//
// Original version
// Joseph Bonneau February 2019
package chatterbox
import (
"crypto/elliptic"
"crypto/sha256"
"fmt"
"math/big"
)
const PRIVATE_KEY_LENGTH = 32 // 256-bit keys
const FINGERPRINT_LENGTH = 16 //128-bit key fingerprints
// Curve in use is NIST-P256
func curve() elliptic.Curve {
return elliptic.P256()
}
// KeyPair represents a public and private key pair. In this application
// we are only doing Diffie-Hellman exchanges. The public key is g^x
// and the private key is the exponent x.
type KeyPair struct {
PrivateKey PrivateKey
PublicKey PublicKey
}
// PrivateKey represents a "private key". This is simply a random buffer
// representing a secret exponent.
type PrivateKey struct {
Key []byte
}
// PublicKey represents a public key, which is an elliptic curve point.
// Represented by two integers X, Y.
type PublicKey struct {
X *big.Int
Y *big.Int
}
// GenerateKeyPair creates a new key pair. It panics in the case of
// randomness failure.
func GenerateKeyPair() *KeyPair {
priv, x, y, err := elliptic.GenerateKey(curve(), RandomnessSource())
if err != nil {
panic(err)
}
r := &KeyPair{
PrivateKey: PrivateKey{Key: priv},
PublicKey: PublicKey{X: x, Y: y},
}
return r
}
// Zeroize overwrites the buffer storing a private key with 0 bytes.
func (k *PrivateKey) Zeroize() {
for i := range k.Key {
k.Key[i] = 0
}
}
// Zeroize overwrites the buffer storing a private key with 0 bytes.
func (kp *KeyPair) Zeroize() {
kp.PrivateKey.Zeroize()
}
// Duplicate produces an exact copy of a given key
func (k *PublicKey) Duplicate() *PublicKey {
r := PublicKey{
X: new(big.Int),
Y: new(big.Int),
}
r.X.Set(k.X)
r.Y.Set(k.Y)
return &r
}
// Duplicate produces an exact copy of a given key
func (k *PrivateKey) Duplicate() *PrivateKey {
r := PrivateKey{
Key: make([]byte, PRIVATE_KEY_LENGTH),
}
copy(r.Key, k.Key)
return &r
}
// Duplicate produces an exact copy of a given key
func (k *KeyPair) Duplicate() *KeyPair {
r := KeyPair{
PrivateKey: PrivateKey{Key: make([]byte, PRIVATE_KEY_LENGTH)},
PublicKey: PublicKey{X: new(big.Int), Y: new(big.Int)},
}
copy(r.PrivateKey.Key, k.PrivateKey.Key)
r.PublicKey.X.Set(k.PublicKey.X)
r.PublicKey.Y.Set(k.PublicKey.Y)
return &r
}
// String representation of a public key.
func (kp *KeyPair) String() string {
return fmt.Sprintf("Public key : % 0X\nPrivate key: % 0X\n", elliptic.Marshal(curve(), kp.PublicKey.X, kp.PublicKey.Y), kp.PrivateKey.Key)
}
// Fingerprint returns a hash representation of a public key.
// This is useful for a shorter value that uniquely identifies the key,
// but cannot be used to recover the key itself.
func (k *PublicKey) Fingerprint() []byte {
h := sha256.New()
h.Write(elliptic.Marshal(curve(), k.X, k.Y))
return h.Sum(nil)[:FINGERPRINT_LENGTH]
}
// Fingerprint returns the fingerprint of the underlying public key.
func (kp *KeyPair) Fingerprint() []byte {
return kp.PublicKey.Fingerprint()
}
// DHCombine performs a Diffie-Hellman exchange between a public key and a
// private key. For example, if the public key is g^a and the private key is
// b, this returns a key derived by hashing g^ab. This is immediatly converted
// to a SymmetricKey.
func DHCombine(publicKey *PublicKey, privateKey *PrivateKey) *SymmetricKey {
x, y := curve().ScalarMult(publicKey.X, publicKey.Y, privateKey.Key)
h := sha256.New()
h.Write(elliptic.Marshal(curve(), x, y))
r := &SymmetricKey{
h.Sum(nil)[:SYMMETRIC_KEY_LENGTH],
}
return r
}