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