...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package elgamal
20
21 import (
22 "crypto/rand"
23 "crypto/subtle"
24 "errors"
25 "io"
26 "math/big"
27 )
28
29
30 type PublicKey struct {
31 G, P, Y *big.Int
32 }
33
34
35 type PrivateKey struct {
36 PublicKey
37 X *big.Int
38 }
39
40
41
42
43 func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
44 pLen := (pub.P.BitLen() + 7) / 8
45 if len(msg) > pLen-11 {
46 err = errors.New("elgamal: message too long")
47 return
48 }
49
50
51 em := make([]byte, pLen-1)
52 em[0] = 2
53 ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
54 err = nonZeroRandomBytes(ps, random)
55 if err != nil {
56 return
57 }
58 em[len(em)-len(msg)-1] = 0
59 copy(mm, msg)
60
61 m := new(big.Int).SetBytes(em)
62
63 k, err := rand.Int(random, pub.P)
64 if err != nil {
65 return
66 }
67
68 c1 = new(big.Int).Exp(pub.G, k, pub.P)
69 s := new(big.Int).Exp(pub.Y, k, pub.P)
70 c2 = s.Mul(s, m)
71 c2.Mod(c2, pub.P)
72
73 return
74 }
75
76
77
78
79
80
81
82
83 func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
84 s := new(big.Int).Exp(c1, priv.X, priv.P)
85 if s.ModInverse(s, priv.P) == nil {
86 return nil, errors.New("elgamal: invalid private key")
87 }
88 s.Mul(s, c2)
89 s.Mod(s, priv.P)
90 em := s.Bytes()
91
92 firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
93
94
95
96
97
98 var lookingForIndex, index int
99 lookingForIndex = 1
100
101 for i := 1; i < len(em); i++ {
102 equals0 := subtle.ConstantTimeByteEq(em[i], 0)
103 index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
104 lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
105 }
106
107 if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
108 return nil, errors.New("elgamal: decryption error")
109 }
110 return em[index+1:], nil
111 }
112
113
114 func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
115 _, err = io.ReadFull(rand, s)
116 if err != nil {
117 return
118 }
119
120 for i := 0; i < len(s); i++ {
121 for s[i] == 0 {
122 _, err = io.ReadFull(rand, s[i:i+1])
123 if err != nil {
124 return
125 }
126 }
127 }
128
129 return
130 }
131
View as plain text