symmetric.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*-
  2. * Copyright 2014 Square Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package jose
  17. import (
  18. "crypto/aes"
  19. "crypto/cipher"
  20. "crypto/hmac"
  21. "crypto/rand"
  22. "crypto/sha256"
  23. "crypto/sha512"
  24. "crypto/subtle"
  25. "errors"
  26. "fmt"
  27. "hash"
  28. "io"
  29. "gopkg.in/square/go-jose.v2/cipher"
  30. )
  31. // Random reader (stubbed out in tests)
  32. var randReader = rand.Reader
  33. // Dummy key cipher for shared symmetric key mode
  34. type symmetricKeyCipher struct {
  35. key []byte // Pre-shared content-encryption key
  36. }
  37. // Signer/verifier for MAC modes
  38. type symmetricMac struct {
  39. key []byte
  40. }
  41. // Input/output from an AEAD operation
  42. type aeadParts struct {
  43. iv, ciphertext, tag []byte
  44. }
  45. // A content cipher based on an AEAD construction
  46. type aeadContentCipher struct {
  47. keyBytes int
  48. authtagBytes int
  49. getAead func(key []byte) (cipher.AEAD, error)
  50. }
  51. // Random key generator
  52. type randomKeyGenerator struct {
  53. size int
  54. }
  55. // Static key generator
  56. type staticKeyGenerator struct {
  57. key []byte
  58. }
  59. // Create a new content cipher based on AES-GCM
  60. func newAESGCM(keySize int) contentCipher {
  61. return &aeadContentCipher{
  62. keyBytes: keySize,
  63. authtagBytes: 16,
  64. getAead: func(key []byte) (cipher.AEAD, error) {
  65. aes, err := aes.NewCipher(key)
  66. if err != nil {
  67. return nil, err
  68. }
  69. return cipher.NewGCM(aes)
  70. },
  71. }
  72. }
  73. // Create a new content cipher based on AES-CBC+HMAC
  74. func newAESCBC(keySize int) contentCipher {
  75. return &aeadContentCipher{
  76. keyBytes: keySize * 2,
  77. authtagBytes: 16,
  78. getAead: func(key []byte) (cipher.AEAD, error) {
  79. return josecipher.NewCBCHMAC(key, aes.NewCipher)
  80. },
  81. }
  82. }
  83. // Get an AEAD cipher object for the given content encryption algorithm
  84. func getContentCipher(alg ContentEncryption) contentCipher {
  85. switch alg {
  86. case A128GCM:
  87. return newAESGCM(16)
  88. case A192GCM:
  89. return newAESGCM(24)
  90. case A256GCM:
  91. return newAESGCM(32)
  92. case A128CBC_HS256:
  93. return newAESCBC(16)
  94. case A192CBC_HS384:
  95. return newAESCBC(24)
  96. case A256CBC_HS512:
  97. return newAESCBC(32)
  98. default:
  99. return nil
  100. }
  101. }
  102. // newSymmetricRecipient creates a JWE encrypter based on AES-GCM key wrap.
  103. func newSymmetricRecipient(keyAlg KeyAlgorithm, key []byte) (recipientKeyInfo, error) {
  104. switch keyAlg {
  105. case DIRECT, A128GCMKW, A192GCMKW, A256GCMKW, A128KW, A192KW, A256KW:
  106. default:
  107. return recipientKeyInfo{}, ErrUnsupportedAlgorithm
  108. }
  109. return recipientKeyInfo{
  110. keyAlg: keyAlg,
  111. keyEncrypter: &symmetricKeyCipher{
  112. key: key,
  113. },
  114. }, nil
  115. }
  116. // newSymmetricSigner creates a recipientSigInfo based on the given key.
  117. func newSymmetricSigner(sigAlg SignatureAlgorithm, key []byte) (recipientSigInfo, error) {
  118. // Verify that key management algorithm is supported by this encrypter
  119. switch sigAlg {
  120. case HS256, HS384, HS512:
  121. default:
  122. return recipientSigInfo{}, ErrUnsupportedAlgorithm
  123. }
  124. return recipientSigInfo{
  125. sigAlg: sigAlg,
  126. signer: &symmetricMac{
  127. key: key,
  128. },
  129. }, nil
  130. }
  131. // Generate a random key for the given content cipher
  132. func (ctx randomKeyGenerator) genKey() ([]byte, rawHeader, error) {
  133. key := make([]byte, ctx.size)
  134. _, err := io.ReadFull(randReader, key)
  135. if err != nil {
  136. return nil, rawHeader{}, err
  137. }
  138. return key, rawHeader{}, nil
  139. }
  140. // Key size for random generator
  141. func (ctx randomKeyGenerator) keySize() int {
  142. return ctx.size
  143. }
  144. // Generate a static key (for direct mode)
  145. func (ctx staticKeyGenerator) genKey() ([]byte, rawHeader, error) {
  146. cek := make([]byte, len(ctx.key))
  147. copy(cek, ctx.key)
  148. return cek, rawHeader{}, nil
  149. }
  150. // Key size for static generator
  151. func (ctx staticKeyGenerator) keySize() int {
  152. return len(ctx.key)
  153. }
  154. // Get key size for this cipher
  155. func (ctx aeadContentCipher) keySize() int {
  156. return ctx.keyBytes
  157. }
  158. // Encrypt some data
  159. func (ctx aeadContentCipher) encrypt(key, aad, pt []byte) (*aeadParts, error) {
  160. // Get a new AEAD instance
  161. aead, err := ctx.getAead(key)
  162. if err != nil {
  163. return nil, err
  164. }
  165. // Initialize a new nonce
  166. iv := make([]byte, aead.NonceSize())
  167. _, err = io.ReadFull(randReader, iv)
  168. if err != nil {
  169. return nil, err
  170. }
  171. ciphertextAndTag := aead.Seal(nil, iv, pt, aad)
  172. offset := len(ciphertextAndTag) - ctx.authtagBytes
  173. return &aeadParts{
  174. iv: iv,
  175. ciphertext: ciphertextAndTag[:offset],
  176. tag: ciphertextAndTag[offset:],
  177. }, nil
  178. }
  179. // Decrypt some data
  180. func (ctx aeadContentCipher) decrypt(key, aad []byte, parts *aeadParts) ([]byte, error) {
  181. aead, err := ctx.getAead(key)
  182. if err != nil {
  183. return nil, err
  184. }
  185. return aead.Open(nil, parts.iv, append(parts.ciphertext, parts.tag...), aad)
  186. }
  187. // Encrypt the content encryption key.
  188. func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
  189. switch alg {
  190. case DIRECT:
  191. return recipientInfo{
  192. header: &rawHeader{},
  193. }, nil
  194. case A128GCMKW, A192GCMKW, A256GCMKW:
  195. aead := newAESGCM(len(ctx.key))
  196. parts, err := aead.encrypt(ctx.key, []byte{}, cek)
  197. if err != nil {
  198. return recipientInfo{}, err
  199. }
  200. header := &rawHeader{}
  201. header.set(headerIV, newBuffer(parts.iv))
  202. header.set(headerTag, newBuffer(parts.tag))
  203. return recipientInfo{
  204. header: header,
  205. encryptedKey: parts.ciphertext,
  206. }, nil
  207. case A128KW, A192KW, A256KW:
  208. block, err := aes.NewCipher(ctx.key)
  209. if err != nil {
  210. return recipientInfo{}, err
  211. }
  212. jek, err := josecipher.KeyWrap(block, cek)
  213. if err != nil {
  214. return recipientInfo{}, err
  215. }
  216. return recipientInfo{
  217. encryptedKey: jek,
  218. header: &rawHeader{},
  219. }, nil
  220. }
  221. return recipientInfo{}, ErrUnsupportedAlgorithm
  222. }
  223. // Decrypt the content encryption key.
  224. func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
  225. switch headers.getAlgorithm() {
  226. case DIRECT:
  227. cek := make([]byte, len(ctx.key))
  228. copy(cek, ctx.key)
  229. return cek, nil
  230. case A128GCMKW, A192GCMKW, A256GCMKW:
  231. aead := newAESGCM(len(ctx.key))
  232. iv, err := headers.getIV()
  233. if err != nil {
  234. return nil, fmt.Errorf("square/go-jose: invalid IV: %v", err)
  235. }
  236. tag, err := headers.getTag()
  237. if err != nil {
  238. return nil, fmt.Errorf("square/go-jose: invalid tag: %v", err)
  239. }
  240. parts := &aeadParts{
  241. iv: iv.bytes(),
  242. ciphertext: recipient.encryptedKey,
  243. tag: tag.bytes(),
  244. }
  245. cek, err := aead.decrypt(ctx.key, []byte{}, parts)
  246. if err != nil {
  247. return nil, err
  248. }
  249. return cek, nil
  250. case A128KW, A192KW, A256KW:
  251. block, err := aes.NewCipher(ctx.key)
  252. if err != nil {
  253. return nil, err
  254. }
  255. cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
  256. if err != nil {
  257. return nil, err
  258. }
  259. return cek, nil
  260. }
  261. return nil, ErrUnsupportedAlgorithm
  262. }
  263. // Sign the given payload
  264. func (ctx symmetricMac) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
  265. mac, err := ctx.hmac(payload, alg)
  266. if err != nil {
  267. return Signature{}, errors.New("square/go-jose: failed to compute hmac")
  268. }
  269. return Signature{
  270. Signature: mac,
  271. protected: &rawHeader{},
  272. }, nil
  273. }
  274. // Verify the given payload
  275. func (ctx symmetricMac) verifyPayload(payload []byte, mac []byte, alg SignatureAlgorithm) error {
  276. expected, err := ctx.hmac(payload, alg)
  277. if err != nil {
  278. return errors.New("square/go-jose: failed to compute hmac")
  279. }
  280. if len(mac) != len(expected) {
  281. return errors.New("square/go-jose: invalid hmac")
  282. }
  283. match := subtle.ConstantTimeCompare(mac, expected)
  284. if match != 1 {
  285. return errors.New("square/go-jose: invalid hmac")
  286. }
  287. return nil
  288. }
  289. // Compute the HMAC based on the given alg value
  290. func (ctx symmetricMac) hmac(payload []byte, alg SignatureAlgorithm) ([]byte, error) {
  291. var hash func() hash.Hash
  292. switch alg {
  293. case HS256:
  294. hash = sha256.New
  295. case HS384:
  296. hash = sha512.New384
  297. case HS512:
  298. hash = sha512.New
  299. default:
  300. return nil, ErrUnsupportedAlgorithm
  301. }
  302. hmac := hmac.New(hash, ctx.key)
  303. // According to documentation, Write() on hash never fails
  304. _, _ = hmac.Write(payload)
  305. return hmac.Sum(nil), nil
  306. }