You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

291 line
7.1 KiB

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