github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go (about) 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 packet 6 7 import ( 8 "crypto/cipher" 9 "crypto/sha1" 10 "crypto/subtle" 11 "golang.org/x/crypto/openpgp/errors" 12 "hash" 13 "io" 14 "strconv" 15 ) 16 17 // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The 18 // encrypted contents will consist of more OpenPGP packets. See RFC 4880, 19 // sections 5.7 and 5.13. 20 type SymmetricallyEncrypted struct { 21 MDC bool // true iff this is a type 18 packet and thus has an embedded MAC. 22 contents io.Reader 23 prefix []byte 24 } 25 26 const symmetricallyEncryptedVersion = 1 27 28 func (se *SymmetricallyEncrypted) parse(r io.Reader) error { 29 if se.MDC { 30 // See RFC 4880, section 5.13. 31 var buf [1]byte 32 _, err := readFull(r, buf[:]) 33 if err != nil { 34 return err 35 } 36 if buf[0] != symmetricallyEncryptedVersion { 37 return errors.UnsupportedError("unknown SymmetricallyEncrypted version") 38 } 39 } 40 se.contents = r 41 return nil 42 } 43 44 // Decrypt returns a ReadCloser, from which the decrypted contents of the 45 // packet can be read. An incorrect key can, with high probability, be detected 46 // immediately and this will result in a KeyIncorrect error being returned. 47 func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { 48 keySize := c.KeySize() 49 if keySize == 0 { 50 return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) 51 } 52 if len(key) != keySize { 53 return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") 54 } 55 56 if se.prefix == nil { 57 se.prefix = make([]byte, c.blockSize()+2) 58 _, err := readFull(se.contents, se.prefix) 59 if err != nil { 60 return nil, err 61 } 62 } else if len(se.prefix) != c.blockSize()+2 { 63 return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") 64 } 65 66 ocfbResync := OCFBResync 67 if se.MDC { 68 // MDC packets use a different form of OCFB mode. 69 ocfbResync = OCFBNoResync 70 } 71 72 s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) 73 if s == nil { 74 return nil, errors.ErrKeyIncorrect 75 } 76 77 plaintext := cipher.StreamReader{S: s, R: se.contents} 78 79 if se.MDC { 80 // MDC packets have an embedded hash that we need to check. 81 h := sha1.New() 82 h.Write(se.prefix) 83 return &seMDCReader{in: plaintext, h: h}, nil 84 } 85 86 // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser. 87 return seReader{plaintext}, nil 88 } 89 90 // seReader wraps an io.Reader with a no-op Close method. 91 type seReader struct { 92 in io.Reader 93 } 94 95 func (ser seReader) Read(buf []byte) (int, error) { 96 return ser.in.Read(buf) 97 } 98 99 func (ser seReader) Close() error { 100 return nil 101 } 102 103 const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size 104 105 // An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold 106 // of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an 107 // MDC packet containing a hash of the previous contents which is checked 108 // against the running hash. See RFC 4880, section 5.13. 109 type seMDCReader struct { 110 in io.Reader 111 h hash.Hash 112 trailer [mdcTrailerSize]byte 113 scratch [mdcTrailerSize]byte 114 trailerUsed int 115 error bool 116 eof bool 117 } 118 119 func (ser *seMDCReader) Read(buf []byte) (n int, err error) { 120 if ser.error { 121 err = io.ErrUnexpectedEOF 122 return 123 } 124 if ser.eof { 125 err = io.EOF 126 return 127 } 128 129 // If we haven't yet filled the trailer buffer then we must do that 130 // first. 131 for ser.trailerUsed < mdcTrailerSize { 132 n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) 133 ser.trailerUsed += n 134 if err == io.EOF { 135 if ser.trailerUsed != mdcTrailerSize { 136 n = 0 137 err = io.ErrUnexpectedEOF 138 ser.error = true 139 return 140 } 141 ser.eof = true 142 n = 0 143 return 144 } 145 146 if err != nil { 147 n = 0 148 return 149 } 150 } 151 152 // If it's a short read then we read into a temporary buffer and shift 153 // the data into the caller's buffer. 154 if len(buf) <= mdcTrailerSize { 155 n, err = readFull(ser.in, ser.scratch[:len(buf)]) 156 copy(buf, ser.trailer[:n]) 157 ser.h.Write(buf[:n]) 158 copy(ser.trailer[:], ser.trailer[n:]) 159 copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) 160 if n < len(buf) { 161 ser.eof = true 162 err = io.EOF 163 } 164 return 165 } 166 167 n, err = ser.in.Read(buf[mdcTrailerSize:]) 168 copy(buf, ser.trailer[:]) 169 ser.h.Write(buf[:n]) 170 copy(ser.trailer[:], buf[n:]) 171 172 if err == io.EOF { 173 ser.eof = true 174 } 175 return 176 } 177 178 // This is a new-format packet tag byte for a type 19 (MDC) packet. 179 const mdcPacketTagByte = byte(0x80) | 0x40 | 19 180 181 func (ser *seMDCReader) Close() error { 182 if ser.error { 183 return errors.SignatureError("error during reading") 184 } 185 186 for !ser.eof { 187 // We haven't seen EOF so we need to read to the end 188 var buf [1024]byte 189 _, err := ser.Read(buf[:]) 190 if err == io.EOF { 191 break 192 } 193 if err != nil { 194 return errors.SignatureError("error during reading") 195 } 196 } 197 198 if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { 199 return errors.SignatureError("MDC packet not found") 200 } 201 ser.h.Write(ser.trailer[:2]) 202 203 final := ser.h.Sum(nil) 204 if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { 205 return errors.SignatureError("hash mismatch") 206 } 207 return nil 208 } 209 210 // An seMDCWriter writes through to an io.WriteCloser while maintains a running 211 // hash of the data written. On close, it emits an MDC packet containing the 212 // running hash. 213 type seMDCWriter struct { 214 w io.WriteCloser 215 h hash.Hash 216 } 217 218 func (w *seMDCWriter) Write(buf []byte) (n int, err error) { 219 w.h.Write(buf) 220 return w.w.Write(buf) 221 } 222 223 func (w *seMDCWriter) Close() (err error) { 224 var buf [mdcTrailerSize]byte 225 226 buf[0] = mdcPacketTagByte 227 buf[1] = sha1.Size 228 w.h.Write(buf[:2]) 229 digest := w.h.Sum(nil) 230 copy(buf[2:], digest) 231 232 _, err = w.w.Write(buf[:]) 233 if err != nil { 234 return 235 } 236 return w.w.Close() 237 } 238 239 // noOpCloser is like an ioutil.NopCloser, but for an io.Writer. 240 type noOpCloser struct { 241 w io.Writer 242 } 243 244 func (c noOpCloser) Write(data []byte) (n int, err error) { 245 return c.w.Write(data) 246 } 247 248 func (c noOpCloser) Close() error { 249 return nil 250 } 251 252 // SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet 253 // to w and returns a WriteCloser to which the to-be-encrypted packets can be 254 // written. 255 // If config is nil, sensible defaults will be used. 256 func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) { 257 if c.KeySize() != len(key) { 258 return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") 259 } 260 writeCloser := noOpCloser{w} 261 ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) 262 if err != nil { 263 return 264 } 265 266 _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) 267 if err != nil { 268 return 269 } 270 271 block := c.new(key) 272 blockSize := block.BlockSize() 273 iv := make([]byte, blockSize) 274 _, err = config.Random().Read(iv) 275 if err != nil { 276 return 277 } 278 s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) 279 _, err = ciphertext.Write(prefix) 280 if err != nil { 281 return 282 } 283 plaintext := cipher.StreamWriter{S: s, W: ciphertext} 284 285 h := sha1.New() 286 h.Write(iv) 287 h.Write(iv[blockSize-2:]) 288 contents = &seMDCWriter{w: plaintext, h: h} 289 return 290 }