aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go122
1 files changed, 122 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 0000000..73f4fe3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
6// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
7// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
8// n. 4, 1985, pp. 469-472.
9//
10// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
11// unsuitable for other protocols. RSA should be used in preference in any
12// case.
13package elgamal // import "golang.org/x/crypto/openpgp/elgamal"
14
15import (
16 "crypto/rand"
17 "crypto/subtle"
18 "errors"
19 "io"
20 "math/big"
21)
22
23// PublicKey represents an ElGamal public key.
24type PublicKey struct {
25 G, P, Y *big.Int
26}
27
28// PrivateKey represents an ElGamal private key.
29type PrivateKey struct {
30 PublicKey
31 X *big.Int
32}
33
34// Encrypt encrypts the given message to the given public key. The result is a
35// pair of integers. Errors can result from reading random, or because msg is
36// too large to be encrypted to the public key.
37func 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 // EM = 0x02 || PS || 0x00 || M
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// Decrypt takes two integers, resulting from an ElGamal encryption, and
71// returns the plaintext of the message. An error can result only if the
72// ciphertext is invalid. Users should keep in mind that this is a padding
73// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
74// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
75// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
76// Bleichenbacher, Advances in Cryptology (Crypto '98),
77func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
78 s := new(big.Int).Exp(c1, priv.X, priv.P)
79 s.ModInverse(s, priv.P)
80 s.Mul(s, c2)
81 s.Mod(s, priv.P)
82 em := s.Bytes()
83
84 firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
85
86 // The remainder of the plaintext must be a string of non-zero random
87 // octets, followed by a 0, followed by the message.
88 // lookingForIndex: 1 iff we are still looking for the zero.
89 // index: the offset of the first zero byte.
90 var lookingForIndex, index int
91 lookingForIndex = 1
92
93 for i := 1; i < len(em); i++ {
94 equals0 := subtle.ConstantTimeByteEq(em[i], 0)
95 index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
96 lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
97 }
98
99 if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
100 return nil, errors.New("elgamal: decryption error")
101 }
102 return em[index+1:], nil
103}
104
105// nonZeroRandomBytes fills the given slice with non-zero random octets.
106func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
107 _, err = io.ReadFull(rand, s)
108 if err != nil {
109 return
110 }
111
112 for i := 0; i < len(s); i++ {
113 for s[i] == 0 {
114 _, err = io.ReadFull(rand, s[i:i+1])
115 if err != nil {
116 return
117 }
118 }
119 }
120
121 return
122}