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.

symmetric_key_encrypted.go 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. "bytes"
  7. "crypto/cipher"
  8. "io"
  9. "strconv"
  10. "github.com/keybase/go-crypto/openpgp/errors"
  11. "github.com/keybase/go-crypto/openpgp/s2k"
  12. )
  13. // This is the largest session key that we'll support. Since no 512-bit cipher
  14. // has even been seriously used, this is comfortably large.
  15. const maxSessionKeySizeInBytes = 64
  16. // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
  17. // 4880, section 5.3.
  18. type SymmetricKeyEncrypted struct {
  19. CipherFunc CipherFunction
  20. s2k func(out, in []byte)
  21. encryptedKey []byte
  22. }
  23. const symmetricKeyEncryptedVersion = 4
  24. func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
  25. // RFC 4880, section 5.3.
  26. var buf [2]byte
  27. if _, err := readFull(r, buf[:]); err != nil {
  28. return err
  29. }
  30. if buf[0] != symmetricKeyEncryptedVersion {
  31. return errors.UnsupportedError("SymmetricKeyEncrypted version")
  32. }
  33. ske.CipherFunc = CipherFunction(buf[1])
  34. if ske.CipherFunc.KeySize() == 0 {
  35. return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
  36. }
  37. var err error
  38. ske.s2k, err = s2k.Parse(r)
  39. if err != nil {
  40. return err
  41. }
  42. if ske.s2k == nil {
  43. return errors.UnsupportedError("can't use dummy S2K for symmetric key encryption")
  44. }
  45. encryptedKey := make([]byte, maxSessionKeySizeInBytes)
  46. // The session key may follow. We just have to try and read to find
  47. // out. If it exists then we limit it to maxSessionKeySizeInBytes.
  48. n, err := readFull(r, encryptedKey)
  49. if err != nil && err != io.ErrUnexpectedEOF {
  50. return err
  51. }
  52. if n != 0 {
  53. if n == maxSessionKeySizeInBytes {
  54. return errors.UnsupportedError("oversized encrypted session key")
  55. }
  56. ske.encryptedKey = encryptedKey[:n]
  57. }
  58. return nil
  59. }
  60. // Decrypt attempts to decrypt an encrypted session key and returns the key and
  61. // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
  62. // packet.
  63. func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
  64. key := make([]byte, ske.CipherFunc.KeySize())
  65. ske.s2k(key, passphrase)
  66. if len(ske.encryptedKey) == 0 {
  67. return key, ske.CipherFunc, nil
  68. }
  69. // the IV is all zeros
  70. iv := make([]byte, ske.CipherFunc.blockSize())
  71. c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
  72. plaintextKey := make([]byte, len(ske.encryptedKey))
  73. c.XORKeyStream(plaintextKey, ske.encryptedKey)
  74. cipherFunc := CipherFunction(plaintextKey[0])
  75. if cipherFunc.blockSize() == 0 {
  76. return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
  77. }
  78. plaintextKey = plaintextKey[1:]
  79. if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() {
  80. return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " +
  81. "not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")")
  82. }
  83. return plaintextKey, cipherFunc, nil
  84. }
  85. // SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
  86. // packet contains a random session key, encrypted by a key derived from the
  87. // given passphrase. The session key is returned and must be passed to
  88. // SerializeSymmetricallyEncrypted.
  89. // If config is nil, sensible defaults will be used.
  90. func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
  91. cipherFunc := config.Cipher()
  92. keySize := cipherFunc.KeySize()
  93. if keySize == 0 {
  94. return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
  95. }
  96. s2kBuf := new(bytes.Buffer)
  97. keyEncryptingKey := make([]byte, keySize)
  98. // s2k.Serialize salts and stretches the passphrase, and writes the
  99. // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
  100. err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
  101. if err != nil {
  102. return
  103. }
  104. s2kBytes := s2kBuf.Bytes()
  105. packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
  106. err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
  107. if err != nil {
  108. return
  109. }
  110. var buf [2]byte
  111. buf[0] = symmetricKeyEncryptedVersion
  112. buf[1] = byte(cipherFunc)
  113. _, err = w.Write(buf[:])
  114. if err != nil {
  115. return
  116. }
  117. _, err = w.Write(s2kBytes)
  118. if err != nil {
  119. return
  120. }
  121. sessionKey := make([]byte, keySize)
  122. _, err = io.ReadFull(config.Random(), sessionKey)
  123. if err != nil {
  124. return
  125. }
  126. iv := make([]byte, cipherFunc.blockSize())
  127. c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
  128. encryptedCipherAndKey := make([]byte, keySize+1)
  129. c.XORKeyStream(encryptedCipherAndKey, buf[1:])
  130. c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
  131. _, err = w.Write(encryptedCipherAndKey)
  132. if err != nil {
  133. return
  134. }
  135. key = sessionKey
  136. return
  137. }