1
2
3
4
5 package packet
6
7 import (
8 "crypto/cipher"
9 "crypto/sha1"
10 "crypto/subtle"
11 "hash"
12 "io"
13 "strconv"
14
15 "github.com/ProtonMail/go-crypto/openpgp/errors"
16 )
17
18
19 type seMdcReader struct {
20 in io.Reader
21 }
22
23 func (ser seMdcReader) Read(buf []byte) (int, error) {
24 return ser.in.Read(buf)
25 }
26
27 func (ser seMdcReader) Close() error {
28 return nil
29 }
30
31 func (se *SymmetricallyEncrypted) decryptMdc(c CipherFunction, key []byte) (io.ReadCloser, error) {
32 if !c.IsSupported() {
33 return nil, errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(c)))
34 }
35
36 if len(key) != c.KeySize() {
37 return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
38 }
39
40 if se.prefix == nil {
41 se.prefix = make([]byte, c.blockSize()+2)
42 _, err := readFull(se.Contents, se.prefix)
43 if err != nil {
44 return nil, err
45 }
46 } else if len(se.prefix) != c.blockSize()+2 {
47 return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
48 }
49
50 ocfbResync := OCFBResync
51 if se.IntegrityProtected {
52
53 ocfbResync = OCFBNoResync
54 }
55
56 s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
57
58 plaintext := cipher.StreamReader{S: s, R: se.Contents}
59
60 if se.IntegrityProtected {
61
62 h := sha1.New()
63 h.Write(se.prefix)
64 return &seMDCReader{in: plaintext, h: h}, nil
65 }
66
67
68 return seMdcReader{plaintext}, nil
69 }
70
71 const mdcTrailerSize = 1 + 1 + sha1.Size
72
73
74
75
76
77 type seMDCReader struct {
78 in io.Reader
79 h hash.Hash
80 trailer [mdcTrailerSize]byte
81 scratch [mdcTrailerSize]byte
82 trailerUsed int
83 error bool
84 eof bool
85 }
86
87 func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
88 if ser.error {
89 err = io.ErrUnexpectedEOF
90 return
91 }
92 if ser.eof {
93 err = io.EOF
94 return
95 }
96
97
98
99 for ser.trailerUsed < mdcTrailerSize {
100 n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
101 ser.trailerUsed += n
102 if err == io.EOF {
103 if ser.trailerUsed != mdcTrailerSize {
104 n = 0
105 err = io.ErrUnexpectedEOF
106 ser.error = true
107 return
108 }
109 ser.eof = true
110 n = 0
111 return
112 }
113
114 if err != nil {
115 n = 0
116 return
117 }
118 }
119
120
121
122 if len(buf) <= mdcTrailerSize {
123 n, err = readFull(ser.in, ser.scratch[:len(buf)])
124 copy(buf, ser.trailer[:n])
125 ser.h.Write(buf[:n])
126 copy(ser.trailer[:], ser.trailer[n:])
127 copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
128 if n < len(buf) {
129 ser.eof = true
130 err = io.EOF
131 }
132 return
133 }
134
135 n, err = ser.in.Read(buf[mdcTrailerSize:])
136 copy(buf, ser.trailer[:])
137 ser.h.Write(buf[:n])
138 copy(ser.trailer[:], buf[n:])
139
140 if err == io.EOF {
141 ser.eof = true
142 }
143 return
144 }
145
146
147 const mdcPacketTagByte = byte(0x80) | 0x40 | 19
148
149 func (ser *seMDCReader) Close() error {
150 if ser.error {
151 return errors.ErrMDCMissing
152 }
153
154 for !ser.eof {
155
156 var buf [1024]byte
157 _, err := ser.Read(buf[:])
158 if err == io.EOF {
159 break
160 }
161 if err != nil {
162 return errors.ErrMDCMissing
163 }
164 }
165
166 ser.h.Write(ser.trailer[:2])
167
168 final := ser.h.Sum(nil)
169 if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
170 return errors.ErrMDCHashMismatch
171 }
172
173
174 if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
175 return errors.ErrMDCMissing
176 }
177 return nil
178 }
179
180
181
182
183 type seMDCWriter struct {
184 w io.WriteCloser
185 h hash.Hash
186 }
187
188 func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
189 w.h.Write(buf)
190 return w.w.Write(buf)
191 }
192
193 func (w *seMDCWriter) Close() (err error) {
194 var buf [mdcTrailerSize]byte
195
196 buf[0] = mdcPacketTagByte
197 buf[1] = sha1.Size
198 w.h.Write(buf[:2])
199 digest := w.h.Sum(nil)
200 copy(buf[2:], digest)
201
202 _, err = w.w.Write(buf[:])
203 if err != nil {
204 return
205 }
206 return w.w.Close()
207 }
208
209
210 type noOpCloser struct {
211 w io.Writer
212 }
213
214 func (c noOpCloser) Write(data []byte) (n int, err error) {
215 return c.w.Write(data)
216 }
217
218 func (c noOpCloser) Close() error {
219 return nil
220 }
221
222 func serializeSymmetricallyEncryptedMdc(ciphertext io.WriteCloser, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) {
223
224 if !c.IsSupported() || c < CipherAES128 {
225 return nil, errors.InvalidArgumentError("invalid mdc cipher function")
226 }
227
228 if c.KeySize() != len(key) {
229 return nil, errors.InvalidArgumentError("error in mdc serialization: bad key length")
230 }
231
232 _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersionMdc})
233 if err != nil {
234 return
235 }
236
237 block := c.new(key)
238 blockSize := block.BlockSize()
239 iv := make([]byte, blockSize)
240 _, err = config.Random().Read(iv)
241 if err != nil {
242 return
243 }
244 s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
245 _, err = ciphertext.Write(prefix)
246 if err != nil {
247 return
248 }
249 plaintext := cipher.StreamWriter{S: s, W: ciphertext}
250
251 h := sha1.New()
252 h.Write(iv)
253 h.Write(iv[blockSize-2:])
254 Contents = &seMDCWriter{w: plaintext, h: h}
255 return
256 }
257
View as plain text