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 "golang.org/x/crypto/openpgp/elgamal"
16 "golang.org/x/crypto/openpgp/errors"
17 )
18
19 const encryptedKeyVersion = 3
20
21
22
23 type EncryptedKey struct {
24 KeyId uint64
25 Algo PublicKeyAlgorithm
26 CipherFunc CipherFunction
27 Key []byte
28
29 encryptedMPI1, encryptedMPI2 parsedMPI
30 }
31
32 func (e *EncryptedKey) parse(r io.Reader) (err error) {
33 var buf [10]byte
34 _, err = readFull(r, buf[:])
35 if err != nil {
36 return
37 }
38 if buf[0] != encryptedKeyVersion {
39 return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
40 }
41 e.KeyId = binary.BigEndian.Uint64(buf[1:9])
42 e.Algo = PublicKeyAlgorithm(buf[9])
43 switch e.Algo {
44 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
45 e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
46 if err != nil {
47 return
48 }
49 case PubKeyAlgoElGamal:
50 e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
51 if err != nil {
52 return
53 }
54 e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
55 if err != nil {
56 return
57 }
58 }
59 _, err = consumeAll(r)
60 return
61 }
62
63 func checksumKeyMaterial(key []byte) uint16 {
64 var checksum uint16
65 for _, v := range key {
66 checksum += uint16(v)
67 }
68 return checksum
69 }
70
71
72
73
74 func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
75 var err error
76 var b []byte
77
78
79
80 switch priv.PubKeyAlgo {
81 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
82
83 k := priv.PrivateKey.(crypto.Decrypter)
84 b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil)
85 case PubKeyAlgoElGamal:
86 c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
87 c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
88 b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
89 default:
90 err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
91 }
92
93 if err != nil {
94 return err
95 }
96
97 e.CipherFunc = CipherFunction(b[0])
98 e.Key = b[1 : len(b)-2]
99 expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
100 checksum := checksumKeyMaterial(e.Key)
101 if checksum != expectedChecksum {
102 return errors.StructuralError("EncryptedKey checksum incorrect")
103 }
104
105 return nil
106 }
107
108
109 func (e *EncryptedKey) Serialize(w io.Writer) error {
110 var mpiLen int
111 switch e.Algo {
112 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
113 mpiLen = 2 + len(e.encryptedMPI1.bytes)
114 case PubKeyAlgoElGamal:
115 mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes)
116 default:
117 return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
118 }
119
120 serializeHeader(w, packetTypeEncryptedKey, 1 +8 +1 +mpiLen)
121
122 w.Write([]byte{encryptedKeyVersion})
123 binary.Write(w, binary.BigEndian, e.KeyId)
124 w.Write([]byte{byte(e.Algo)})
125
126 switch e.Algo {
127 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
128 writeMPIs(w, e.encryptedMPI1)
129 case PubKeyAlgoElGamal:
130 writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2)
131 default:
132 panic("internal error")
133 }
134
135 return nil
136 }
137
138
139
140
141 func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
142 var buf [10]byte
143 buf[0] = encryptedKeyVersion
144 binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
145 buf[9] = byte(pub.PubKeyAlgo)
146
147 keyBlock := make([]byte, 1 +len(key)+2 )
148 keyBlock[0] = byte(cipherFunc)
149 copy(keyBlock[1:], key)
150 checksum := checksumKeyMaterial(key)
151 keyBlock[1+len(key)] = byte(checksum >> 8)
152 keyBlock[1+len(key)+1] = byte(checksum)
153
154 switch pub.PubKeyAlgo {
155 case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
156 return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
157 case PubKeyAlgoElGamal:
158 return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
159 case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
160 return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
161 }
162
163 return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
164 }
165
166 func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
167 cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
168 if err != nil {
169 return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
170 }
171
172 packetLen := 10 + 2 + len(cipherText)
173
174 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
175 if err != nil {
176 return err
177 }
178 _, err = w.Write(header[:])
179 if err != nil {
180 return err
181 }
182 return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
183 }
184
185 func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
186 c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
187 if err != nil {
188 return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
189 }
190
191 packetLen := 10
192 packetLen += 2 + (c1.BitLen()+7)/8
193 packetLen += 2 + (c2.BitLen()+7)/8
194
195 err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
196 if err != nil {
197 return err
198 }
199 _, err = w.Write(header[:])
200 if err != nil {
201 return err
202 }
203 err = writeBig(w, c1)
204 if err != nil {
205 return err
206 }
207 return writeBig(w, c2)
208 }
209
View as plain text