1
2
3
4
5 package packet
6
7 import (
8 "crypto"
9 "crypto/rsa"
10 "encoding/binary"
11 "io"
12 "math/big"
13 "strconv"
14
15 "github.com/ProtonMail/go-crypto/openpgp/ecdh"
16 "github.com/ProtonMail/go-crypto/openpgp/elgamal"
17 "github.com/ProtonMail/go-crypto/openpgp/errors"
18 "github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
19 )
20
21 const encryptedKeyVersion = 3
22
23
24
25 type EncryptedKey struct {
26 KeyId uint64
27 Algo PublicKeyAlgorithm
28 CipherFunc CipherFunction
29 Key []byte
30
31 encryptedMPI1, encryptedMPI2 encoding.Field
32 }
33
34 func (e *EncryptedKey) parse(r io.Reader) (err error) {
35 var buf [10]byte
36 _, err = readFull(r, buf[:])
37 if err != nil {
38 return
39 }
40 if buf[0] != encryptedKeyVersion {
41 return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
42 }
43 e.KeyId = binary.BigEndian.Uint64(buf[1:9])
44 e.Algo = PublicKeyAlgorithm(buf[9])
45 switch e.Algo {
46 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
47 e.encryptedMPI1 = new(encoding.MPI)
48 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
49 return
50 }
51 case PubKeyAlgoElGamal:
52 e.encryptedMPI1 = new(encoding.MPI)
53 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
54 return
55 }
56
57 e.encryptedMPI2 = new(encoding.MPI)
58 if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
59 return
60 }
61 case PubKeyAlgoECDH:
62 e.encryptedMPI1 = new(encoding.MPI)
63 if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
64 return
65 }
66
67 e.encryptedMPI2 = new(encoding.OID)
68 if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
69 return
70 }
71 }
72 _, err = consumeAll(r)
73 return
74 }
75
76 func checksumKeyMaterial(key []byte) uint16 {
77 var checksum uint16
78 for _, v := range key {
79 checksum += uint16(v)
80 }
81 return checksum
82 }
83
84
85
86
87 func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
88 if e.KeyId != 0 && e.KeyId != priv.KeyId {
89 return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
90 }
91 if e.Algo != priv.PubKeyAlgo {
92 return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
93 }
94 if priv.Dummy() {
95 return errors.ErrDummyPrivateKey("dummy key found")
96 }
97
98 var err error
99 var b []byte
100
101
102
103 switch priv.PubKeyAlgo {
104 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
105
106 k := priv.PrivateKey.(crypto.Decrypter)
107 b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil)
108 case PubKeyAlgoElGamal:
109 c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes())
110 c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes())
111 b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
112 case PubKeyAlgoECDH:
113 vsG := e.encryptedMPI1.Bytes()
114 m := e.encryptedMPI2.Bytes()
115 oid := priv.PublicKey.oid.EncodedBytes()
116 b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:])
117 default:
118 err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
119 }
120
121 if err != nil {
122 return err
123 }
124
125 e.CipherFunc = CipherFunction(b[0])
126 if !e.CipherFunc.IsSupported() {
127 return errors.UnsupportedError("unsupported encryption function")
128 }
129
130 e.Key = b[1 : len(b)-2]
131 expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
132 checksum := checksumKeyMaterial(e.Key)
133 if checksum != expectedChecksum {
134 return errors.StructuralError("EncryptedKey checksum incorrect")
135 }
136
137 return nil
138 }
139
140
141 func (e *EncryptedKey) Serialize(w io.Writer) error {
142 var mpiLen int
143 switch e.Algo {
144 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
145 mpiLen = int(e.encryptedMPI1.EncodedLength())
146 case PubKeyAlgoElGamal:
147 mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
148 case PubKeyAlgoECDH:
149 mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
150 default:
151 return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
152 }
153
154 err := serializeHeader(w, packetTypeEncryptedKey, 1 +8 +1 +mpiLen)
155 if err != nil {
156 return err
157 }
158
159 w.Write([]byte{encryptedKeyVersion})
160 binary.Write(w, binary.BigEndian, e.KeyId)
161 w.Write([]byte{byte(e.Algo)})
162
163 switch e.Algo {
164 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
165 _, err := w.Write(e.encryptedMPI1.EncodedBytes())
166 return err
167 case PubKeyAlgoElGamal:
168 if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
169 return err
170 }
171 _, err := w.Write(e.encryptedMPI2.EncodedBytes())
172 return err
173 case PubKeyAlgoECDH:
174 if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
175 return err
176 }
177 _, err := w.Write(e.encryptedMPI2.EncodedBytes())
178 return err
179 default:
180 panic("internal error")
181 }
182 }
183
184
185
186
187 func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
188 var buf [10]byte
189 buf[0] = encryptedKeyVersion
190 binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
191 buf[9] = byte(pub.PubKeyAlgo)
192
193 keyBlock := make([]byte, 1 +len(key)+2 )
194 keyBlock[0] = byte(cipherFunc)
195 copy(keyBlock[1:], key)
196 checksum := checksumKeyMaterial(key)
197 keyBlock[1+len(key)] = byte(checksum >> 8)
198 keyBlock[1+len(key)+1] = byte(checksum)
199
200 switch pub.PubKeyAlgo {
201 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
202 return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
203 case PubKeyAlgoElGamal:
204 return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
205 case PubKeyAlgoECDH:
206 return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
207 case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
208 return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
209 }
210
211 return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
212 }
213
214 func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
215 cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
216 if err != nil {
217 return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
218 }
219
220 cipherMPI := encoding.NewMPI(cipherText)
221 packetLen := 10 + int(cipherMPI.EncodedLength())
222
223 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
224 if err != nil {
225 return err
226 }
227 _, err = w.Write(header[:])
228 if err != nil {
229 return err
230 }
231 _, err = w.Write(cipherMPI.EncodedBytes())
232 return err
233 }
234
235 func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
236 c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
237 if err != nil {
238 return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
239 }
240
241 packetLen := 10
242 packetLen += 2 + (c1.BitLen()+7)/8
243 packetLen += 2 + (c2.BitLen()+7)/8
244
245 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
246 if err != nil {
247 return err
248 }
249 _, err = w.Write(header[:])
250 if err != nil {
251 return err
252 }
253 if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil {
254 return err
255 }
256 _, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes())
257 return err
258 }
259
260 func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
261 vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
262 if err != nil {
263 return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
264 }
265
266 g := encoding.NewMPI(vsG)
267 m := encoding.NewOID(c)
268
269 packetLen := 10
270 packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
271
272 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
273 if err != nil {
274 return err
275 }
276
277 _, err = w.Write(header[:])
278 if err != nil {
279 return err
280 }
281 if _, err = w.Write(g.EncodedBytes()); err != nil {
282 return err
283 }
284 _, err = w.Write(m.EncodedBytes())
285 return err
286 }
287
View as plain text