-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
145 lines (120 loc) · 3.15 KB
/
main.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
package main
import (
"crypto/aes"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
)
// Vaudenay SAS protocol (https://www.iacr.org/archive/crypto2005/36210303/36210303.pdf)
// Improved by MA-3 protocol (https://eprint.iacr.org/2005/424.pdf)
// Based on an Ideal Commitment Model.
// The exchanged messages could be the hashes of public keys.
func main() {
alice := newPerson("AlicePublicKey")
bob := newPerson("BobPublicKey")
// Alice sends commitment and message to Bob
alice.commitTo(bob)
// Bob sends message and nonce to Alice
bob.sendTo(alice)
// Alice reveals the nonce to Bob
alice.commitment.decommit()
// Both parties calculate the pin
fmt.Println(alice.initiatorCheck())
fmt.Println(bob.secondaryCheck())
}
type person struct {
r []byte
msg []byte
commitment *commitment
other *person
}
func newPerson(msg string) *person {
r := make([]byte, aes.BlockSize)
_, err := rand.Read(r)
if err != nil {
panic(err.Error())
}
return &person{
r: r,
msg: []byte(msg),
other: &person{},
}
}
// commitTo sends the message and the newly created commitment to the other person
func (p *person) commitTo(the *person) {
p.commitment = newCommitment(p.r)
the.other.commitment = p.commitment
the.other.msg = p.msg
}
// sendTo sends the message and the nonce to the other person
func (p *person) sendTo(the *person) {
the.other.msg = p.msg
the.other.r = p.r
}
// initiatorCheck calculates the pin for the initiator of the protocol
func (p *person) initiatorCheck() string {
c, err := aes.NewCipher(p.r)
if err != nil {
panic(err.Error())
}
aKey := make([]byte, c.BlockSize())
c.Encrypt(aKey, p.other.r)
aCheck := hmac.New(sha256.New, aKey)
aCheck.Write(p.msg)
aCheck.Write(p.other.msg)
return retrievePin(aCheck.Sum(nil), 8)
}
// secondaryCheck calculates the pin for the secondary of the protocol
func (p *person) secondaryCheck() string {
aRand, err := p.other.commitment.open()
if err != nil {
panic(err.Error())
}
c, err := aes.NewCipher(aRand)
if err != nil {
panic(err.Error())
}
bKey := make([]byte, c.BlockSize())
c.Encrypt(bKey, p.r)
bCheck := hmac.New(sha256.New, bKey)
bCheck.Write(p.other.msg)
bCheck.Write(p.msg)
return retrievePin(bCheck.Sum(nil), 8)
}
// retrievePin returns a pin of the specified length based on the given (random) bytes
func retrievePin(r []byte, maxLength int) string {
// Create a string containing only the digits 0-9
digitString := ""
for _, b := range r {
digitString += fmt.Sprintf("%d", int(b)%10)
if len(digitString) == maxLength {
break
}
}
return digitString
}
// commitment models an ideal commitment scheme
type commitment struct {
message []byte
isProtected bool
}
// open returns the message if the commitment is not protected
func (c *commitment) open() ([]byte, error) {
if c.isProtected {
return nil, errors.New("commitment is protected")
}
return c.message, nil
}
// decommit makes the commitment unprotected
func (c *commitment) decommit() {
c.isProtected = false
}
// newCommitment creates a new protected commitment
func newCommitment(c []byte) *commitment {
return &commitment{
message: c,
isProtected: true,
}
}