s2k.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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 s2k implements the various OpenPGP string-to-key transforms as
  5. // specified in RFC 4800 section 3.7.1.
  6. package s2k
  7. import (
  8. "crypto"
  9. "hash"
  10. "io"
  11. "strconv"
  12. "golang.org/x/crypto/openpgp/errors"
  13. )
  14. // Config collects configuration parameters for s2k key-stretching
  15. // transformatioms. A nil *Config is valid and results in all default
  16. // values. Currently, Config is used only by the Serialize function in
  17. // this package.
  18. type Config struct {
  19. // Hash is the default hash function to be used. If
  20. // nil, SHA1 is used.
  21. Hash crypto.Hash
  22. }
  23. func (c *Config) hash() crypto.Hash {
  24. if c == nil || uint(c.Hash) == 0 {
  25. // SHA1 is the historical default in this package.
  26. return crypto.SHA1
  27. }
  28. return c.Hash
  29. }
  30. // Simple writes to out the result of computing the Simple S2K function (RFC
  31. // 4880, section 3.7.1.1) using the given hash and input passphrase.
  32. func Simple(out []byte, h hash.Hash, in []byte) {
  33. Salted(out, h, in, nil)
  34. }
  35. var zero [1]byte
  36. // Salted writes to out the result of computing the Salted S2K function (RFC
  37. // 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
  38. func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
  39. done := 0
  40. var digest []byte
  41. for i := 0; done < len(out); i++ {
  42. h.Reset()
  43. for j := 0; j < i; j++ {
  44. h.Write(zero[:])
  45. }
  46. h.Write(salt)
  47. h.Write(in)
  48. digest = h.Sum(digest[:0])
  49. n := copy(out[done:], digest)
  50. done += n
  51. }
  52. }
  53. // Iterated writes to out the result of computing the Iterated and Salted S2K
  54. // function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
  55. // salt and iteration count.
  56. func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
  57. combined := make([]byte, len(in)+len(salt))
  58. copy(combined, salt)
  59. copy(combined[len(salt):], in)
  60. if count < len(combined) {
  61. count = len(combined)
  62. }
  63. done := 0
  64. var digest []byte
  65. for i := 0; done < len(out); i++ {
  66. h.Reset()
  67. for j := 0; j < i; j++ {
  68. h.Write(zero[:])
  69. }
  70. written := 0
  71. for written < count {
  72. if written+len(combined) > count {
  73. todo := count - written
  74. h.Write(combined[:todo])
  75. written = count
  76. } else {
  77. h.Write(combined)
  78. written += len(combined)
  79. }
  80. }
  81. digest = h.Sum(digest[:0])
  82. n := copy(out[done:], digest)
  83. done += n
  84. }
  85. }
  86. // Parse reads a binary specification for a string-to-key transformation from r
  87. // and returns a function which performs that transform.
  88. func Parse(r io.Reader) (f func(out, in []byte), err error) {
  89. var buf [9]byte
  90. _, err = io.ReadFull(r, buf[:2])
  91. if err != nil {
  92. return
  93. }
  94. hash, ok := HashIdToHash(buf[1])
  95. if !ok {
  96. return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
  97. }
  98. if !hash.Available() {
  99. return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
  100. }
  101. h := hash.New()
  102. switch buf[0] {
  103. case 0:
  104. f := func(out, in []byte) {
  105. Simple(out, h, in)
  106. }
  107. return f, nil
  108. case 1:
  109. _, err = io.ReadFull(r, buf[:8])
  110. if err != nil {
  111. return
  112. }
  113. f := func(out, in []byte) {
  114. Salted(out, h, in, buf[:8])
  115. }
  116. return f, nil
  117. case 3:
  118. _, err = io.ReadFull(r, buf[:9])
  119. if err != nil {
  120. return
  121. }
  122. count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6)
  123. f := func(out, in []byte) {
  124. Iterated(out, h, in, buf[:8], count)
  125. }
  126. return f, nil
  127. }
  128. return nil, errors.UnsupportedError("S2K function")
  129. }
  130. // Serialize salts and stretches the given passphrase and writes the
  131. // resulting key into key. It also serializes an S2K descriptor to
  132. // w. The key stretching can be configured with c, which may be
  133. // nil. In that case, sensible defaults will be used.
  134. func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
  135. var buf [11]byte
  136. buf[0] = 3 /* iterated and salted */
  137. buf[1], _ = HashToHashId(c.hash())
  138. salt := buf[2:10]
  139. if _, err := io.ReadFull(rand, salt); err != nil {
  140. return err
  141. }
  142. const count = 65536 // this is the default in gpg
  143. buf[10] = 96 // 65536 iterations
  144. if _, err := w.Write(buf[:]); err != nil {
  145. return err
  146. }
  147. Iterated(key, c.hash().New(), passphrase, salt, count)
  148. return nil
  149. }
  150. // hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
  151. // Go's crypto.Hash type. See RFC 4880, section 9.4.
  152. var hashToHashIdMapping = []struct {
  153. id byte
  154. hash crypto.Hash
  155. name string
  156. }{
  157. {1, crypto.MD5, "MD5"},
  158. {2, crypto.SHA1, "SHA1"},
  159. {3, crypto.RIPEMD160, "RIPEMD160"},
  160. {8, crypto.SHA256, "SHA256"},
  161. {9, crypto.SHA384, "SHA384"},
  162. {10, crypto.SHA512, "SHA512"},
  163. {11, crypto.SHA224, "SHA224"},
  164. }
  165. // HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
  166. // hash id.
  167. func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
  168. for _, m := range hashToHashIdMapping {
  169. if m.id == id {
  170. return m.hash, true
  171. }
  172. }
  173. return 0, false
  174. }
  175. // HashIdToString returns the name of the hash function corresponding to the
  176. // given OpenPGP hash id, or panics if id is unknown.
  177. func HashIdToString(id byte) (name string, ok bool) {
  178. for _, m := range hashToHashIdMapping {
  179. if m.id == id {
  180. return m.name, true
  181. }
  182. }
  183. return "", false
  184. }
  185. // HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
  186. func HashToHashId(h crypto.Hash) (id byte, ok bool) {
  187. for _, m := range hashToHashIdMapping {
  188. if m.hash == h {
  189. return m.id, true
  190. }
  191. }
  192. return 0, false
  193. }