symmetric.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  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. "bytes"
  19. "crypto/aes"
  20. "crypto/cipher"
  21. "crypto/hmac"
  22. "crypto/rand"
  23. "crypto/sha256"
  24. "crypto/sha512"
  25. "crypto/subtle"
  26. "errors"
  27. "fmt"
  28. "hash"
  29. "io"
  30. "golang.org/x/crypto/pbkdf2"
  31. "gopkg.in/square/go-jose.v2/cipher"
  32. )
  33. // Random reader (stubbed out in tests)
  34. var RandReader = rand.Reader
  35. const (
  36. // RFC7518 recommends a minimum of 1,000 iterations:
  37. // https://tools.ietf.org/html/rfc7518#section-4.8.1.2
  38. // NIST recommends a minimum of 10,000:
  39. // https://pages.nist.gov/800-63-3/sp800-63b.html
  40. // 1Password uses 100,000:
  41. // https://support.1password.com/pbkdf2/
  42. defaultP2C = 100000
  43. // Default salt size: 128 bits
  44. defaultP2SSize = 16
  45. )
  46. // Dummy key cipher for shared symmetric key mode
  47. type symmetricKeyCipher struct {
  48. key []byte // Pre-shared content-encryption key
  49. p2c int // PBES2 Count
  50. p2s []byte // PBES2 Salt Input
  51. }
  52. // Signer/verifier for MAC modes
  53. type symmetricMac struct {
  54. key []byte
  55. }
  56. // Input/output from an AEAD operation
  57. type aeadParts struct {
  58. iv, ciphertext, tag []byte
  59. }
  60. // A content cipher based on an AEAD construction
  61. type aeadContentCipher struct {
  62. keyBytes int
  63. authtagBytes int
  64. getAead func(key []byte) (cipher.AEAD, error)
  65. }
  66. // Random key generator
  67. type randomKeyGenerator struct {
  68. size int
  69. }
  70. // Static key generator
  71. type staticKeyGenerator struct {
  72. key []byte
  73. }
  74. // Create a new content cipher based on AES-GCM
  75. func newAESGCM(keySize int) contentCipher {
  76. return &aeadContentCipher{
  77. keyBytes: keySize,
  78. authtagBytes: 16,
  79. getAead: func(key []byte) (cipher.AEAD, error) {
  80. aes, err := aes.NewCipher(key)
  81. if err != nil {
  82. return nil, err
  83. }
  84. return cipher.NewGCM(aes)
  85. },
  86. }
  87. }
  88. // Create a new content cipher based on AES-CBC+HMAC
  89. func newAESCBC(keySize int) contentCipher {
  90. return &aeadContentCipher{
  91. keyBytes: keySize * 2,
  92. authtagBytes: keySize,
  93. getAead: func(key []byte) (cipher.AEAD, error) {
  94. return josecipher.NewCBCHMAC(key, aes.NewCipher)
  95. },
  96. }
  97. }
  98. // Get an AEAD cipher object for the given content encryption algorithm
  99. func getContentCipher(alg ContentEncryption) contentCipher {
  100. switch alg {
  101. case A128GCM:
  102. return newAESGCM(16)
  103. case A192GCM:
  104. return newAESGCM(24)
  105. case A256GCM:
  106. return newAESGCM(32)
  107. case A128CBC_HS256:
  108. return newAESCBC(16)
  109. case A192CBC_HS384:
  110. return newAESCBC(24)
  111. case A256CBC_HS512:
  112. return newAESCBC(32)
  113. default:
  114. return nil
  115. }
  116. }
  117. // getPbkdf2Params returns the key length and hash function used in
  118. // pbkdf2.Key.
  119. func getPbkdf2Params(alg KeyAlgorithm) (int, func() hash.Hash) {
  120. switch alg {
  121. case PBES2_HS256_A128KW:
  122. return 16, sha256.New
  123. case PBES2_HS384_A192KW:
  124. return 24, sha512.New384
  125. case PBES2_HS512_A256KW:
  126. return 32, sha512.New
  127. default:
  128. panic("invalid algorithm")
  129. }
  130. }
  131. // getRandomSalt generates a new salt of the given size.
  132. func getRandomSalt(size int) ([]byte, error) {
  133. salt := make([]byte, size)
  134. _, err := io.ReadFull(RandReader, salt)
  135. if err != nil {
  136. return nil, err
  137. }
  138. return salt, nil
  139. }
  140. // newSymmetricRecipient creates a JWE encrypter based on AES-GCM key wrap.
  141. func newSymmetricRecipient(keyAlg KeyAlgorithm, key []byte) (recipientKeyInfo, error) {
  142. switch keyAlg {
  143. case DIRECT, A128GCMKW, A192GCMKW, A256GCMKW, A128KW, A192KW, A256KW:
  144. case PBES2_HS256_A128KW, PBES2_HS384_A192KW, PBES2_HS512_A256KW:
  145. default:
  146. return recipientKeyInfo{}, ErrUnsupportedAlgorithm
  147. }
  148. return recipientKeyInfo{
  149. keyAlg: keyAlg,
  150. keyEncrypter: &symmetricKeyCipher{
  151. key: key,
  152. },
  153. }, nil
  154. }
  155. // newSymmetricSigner creates a recipientSigInfo based on the given key.
  156. func newSymmetricSigner(sigAlg SignatureAlgorithm, key []byte) (recipientSigInfo, error) {
  157. // Verify that key management algorithm is supported by this encrypter
  158. switch sigAlg {
  159. case HS256, HS384, HS512:
  160. default:
  161. return recipientSigInfo{}, ErrUnsupportedAlgorithm
  162. }
  163. return recipientSigInfo{
  164. sigAlg: sigAlg,
  165. signer: &symmetricMac{
  166. key: key,
  167. },
  168. }, nil
  169. }
  170. // Generate a random key for the given content cipher
  171. func (ctx randomKeyGenerator) genKey() ([]byte, rawHeader, error) {
  172. key := make([]byte, ctx.size)
  173. _, err := io.ReadFull(RandReader, key)
  174. if err != nil {
  175. return nil, rawHeader{}, err
  176. }
  177. return key, rawHeader{}, nil
  178. }
  179. // Key size for random generator
  180. func (ctx randomKeyGenerator) keySize() int {
  181. return ctx.size
  182. }
  183. // Generate a static key (for direct mode)
  184. func (ctx staticKeyGenerator) genKey() ([]byte, rawHeader, error) {
  185. cek := make([]byte, len(ctx.key))
  186. copy(cek, ctx.key)
  187. return cek, rawHeader{}, nil
  188. }
  189. // Key size for static generator
  190. func (ctx staticKeyGenerator) keySize() int {
  191. return len(ctx.key)
  192. }
  193. // Get key size for this cipher
  194. func (ctx aeadContentCipher) keySize() int {
  195. return ctx.keyBytes
  196. }
  197. // Encrypt some data
  198. func (ctx aeadContentCipher) encrypt(key, aad, pt []byte) (*aeadParts, error) {
  199. // Get a new AEAD instance
  200. aead, err := ctx.getAead(key)
  201. if err != nil {
  202. return nil, err
  203. }
  204. // Initialize a new nonce
  205. iv := make([]byte, aead.NonceSize())
  206. _, err = io.ReadFull(RandReader, iv)
  207. if err != nil {
  208. return nil, err
  209. }
  210. ciphertextAndTag := aead.Seal(nil, iv, pt, aad)
  211. offset := len(ciphertextAndTag) - ctx.authtagBytes
  212. return &aeadParts{
  213. iv: iv,
  214. ciphertext: ciphertextAndTag[:offset],
  215. tag: ciphertextAndTag[offset:],
  216. }, nil
  217. }
  218. // Decrypt some data
  219. func (ctx aeadContentCipher) decrypt(key, aad []byte, parts *aeadParts) ([]byte, error) {
  220. aead, err := ctx.getAead(key)
  221. if err != nil {
  222. return nil, err
  223. }
  224. if len(parts.iv) != aead.NonceSize() || len(parts.tag) < ctx.authtagBytes {
  225. return nil, ErrCryptoFailure
  226. }
  227. return aead.Open(nil, parts.iv, append(parts.ciphertext, parts.tag...), aad)
  228. }
  229. // Encrypt the content encryption key.
  230. func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
  231. switch alg {
  232. case DIRECT:
  233. return recipientInfo{
  234. header: &rawHeader{},
  235. }, nil
  236. case A128GCMKW, A192GCMKW, A256GCMKW:
  237. aead := newAESGCM(len(ctx.key))
  238. parts, err := aead.encrypt(ctx.key, []byte{}, cek)
  239. if err != nil {
  240. return recipientInfo{}, err
  241. }
  242. header := &rawHeader{}
  243. header.set(headerIV, newBuffer(parts.iv))
  244. header.set(headerTag, newBuffer(parts.tag))
  245. return recipientInfo{
  246. header: header,
  247. encryptedKey: parts.ciphertext,
  248. }, nil
  249. case A128KW, A192KW, A256KW:
  250. block, err := aes.NewCipher(ctx.key)
  251. if err != nil {
  252. return recipientInfo{}, err
  253. }
  254. jek, err := josecipher.KeyWrap(block, cek)
  255. if err != nil {
  256. return recipientInfo{}, err
  257. }
  258. return recipientInfo{
  259. encryptedKey: jek,
  260. header: &rawHeader{},
  261. }, nil
  262. case PBES2_HS256_A128KW, PBES2_HS384_A192KW, PBES2_HS512_A256KW:
  263. if len(ctx.p2s) == 0 {
  264. salt, err := getRandomSalt(defaultP2SSize)
  265. if err != nil {
  266. return recipientInfo{}, err
  267. }
  268. ctx.p2s = salt
  269. }
  270. if ctx.p2c <= 0 {
  271. ctx.p2c = defaultP2C
  272. }
  273. // salt is UTF8(Alg) || 0x00 || Salt Input
  274. salt := bytes.Join([][]byte{[]byte(alg), ctx.p2s}, []byte{0x00})
  275. // derive key
  276. keyLen, h := getPbkdf2Params(alg)
  277. key := pbkdf2.Key(ctx.key, salt, ctx.p2c, keyLen, h)
  278. // use AES cipher with derived key
  279. block, err := aes.NewCipher(key)
  280. if err != nil {
  281. return recipientInfo{}, err
  282. }
  283. jek, err := josecipher.KeyWrap(block, cek)
  284. if err != nil {
  285. return recipientInfo{}, err
  286. }
  287. header := &rawHeader{}
  288. header.set(headerP2C, ctx.p2c)
  289. header.set(headerP2S, newBuffer(ctx.p2s))
  290. return recipientInfo{
  291. encryptedKey: jek,
  292. header: header,
  293. }, nil
  294. }
  295. return recipientInfo{}, ErrUnsupportedAlgorithm
  296. }
  297. // Decrypt the content encryption key.
  298. func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
  299. switch headers.getAlgorithm() {
  300. case DIRECT:
  301. cek := make([]byte, len(ctx.key))
  302. copy(cek, ctx.key)
  303. return cek, nil
  304. case A128GCMKW, A192GCMKW, A256GCMKW:
  305. aead := newAESGCM(len(ctx.key))
  306. iv, err := headers.getIV()
  307. if err != nil {
  308. return nil, fmt.Errorf("square/go-jose: invalid IV: %v", err)
  309. }
  310. tag, err := headers.getTag()
  311. if err != nil {
  312. return nil, fmt.Errorf("square/go-jose: invalid tag: %v", err)
  313. }
  314. parts := &aeadParts{
  315. iv: iv.bytes(),
  316. ciphertext: recipient.encryptedKey,
  317. tag: tag.bytes(),
  318. }
  319. cek, err := aead.decrypt(ctx.key, []byte{}, parts)
  320. if err != nil {
  321. return nil, err
  322. }
  323. return cek, nil
  324. case A128KW, A192KW, A256KW:
  325. block, err := aes.NewCipher(ctx.key)
  326. if err != nil {
  327. return nil, err
  328. }
  329. cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
  330. if err != nil {
  331. return nil, err
  332. }
  333. return cek, nil
  334. case PBES2_HS256_A128KW, PBES2_HS384_A192KW, PBES2_HS512_A256KW:
  335. p2s, err := headers.getP2S()
  336. if err != nil {
  337. return nil, fmt.Errorf("square/go-jose: invalid P2S: %v", err)
  338. }
  339. if p2s == nil || len(p2s.data) == 0 {
  340. return nil, fmt.Errorf("square/go-jose: invalid P2S: must be present")
  341. }
  342. p2c, err := headers.getP2C()
  343. if err != nil {
  344. return nil, fmt.Errorf("square/go-jose: invalid P2C: %v", err)
  345. }
  346. if p2c <= 0 {
  347. return nil, fmt.Errorf("square/go-jose: invalid P2C: must be a positive integer")
  348. }
  349. // salt is UTF8(Alg) || 0x00 || Salt Input
  350. alg := headers.getAlgorithm()
  351. salt := bytes.Join([][]byte{[]byte(alg), p2s.bytes()}, []byte{0x00})
  352. // derive key
  353. keyLen, h := getPbkdf2Params(alg)
  354. key := pbkdf2.Key(ctx.key, salt, p2c, keyLen, h)
  355. // use AES cipher with derived key
  356. block, err := aes.NewCipher(key)
  357. if err != nil {
  358. return nil, err
  359. }
  360. cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
  361. if err != nil {
  362. return nil, err
  363. }
  364. return cek, nil
  365. }
  366. return nil, ErrUnsupportedAlgorithm
  367. }
  368. // Sign the given payload
  369. func (ctx symmetricMac) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
  370. mac, err := ctx.hmac(payload, alg)
  371. if err != nil {
  372. return Signature{}, errors.New("square/go-jose: failed to compute hmac")
  373. }
  374. return Signature{
  375. Signature: mac,
  376. protected: &rawHeader{},
  377. }, nil
  378. }
  379. // Verify the given payload
  380. func (ctx symmetricMac) verifyPayload(payload []byte, mac []byte, alg SignatureAlgorithm) error {
  381. expected, err := ctx.hmac(payload, alg)
  382. if err != nil {
  383. return errors.New("square/go-jose: failed to compute hmac")
  384. }
  385. if len(mac) != len(expected) {
  386. return errors.New("square/go-jose: invalid hmac")
  387. }
  388. match := subtle.ConstantTimeCompare(mac, expected)
  389. if match != 1 {
  390. return errors.New("square/go-jose: invalid hmac")
  391. }
  392. return nil
  393. }
  394. // Compute the HMAC based on the given alg value
  395. func (ctx symmetricMac) hmac(payload []byte, alg SignatureAlgorithm) ([]byte, error) {
  396. var hash func() hash.Hash
  397. switch alg {
  398. case HS256:
  399. hash = sha256.New
  400. case HS384:
  401. hash = sha512.New384
  402. case HS512:
  403. hash = sha512.New
  404. default:
  405. return nil, ErrUnsupportedAlgorithm
  406. }
  407. hmac := hmac.New(hash, ctx.key)
  408. // According to documentation, Write() on hash never fails
  409. _, _ = hmac.Write(payload)
  410. return hmac.Sum(nil), nil
  411. }