key_wrap.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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 josecipher
  17. import (
  18. "crypto/cipher"
  19. "crypto/subtle"
  20. "encoding/binary"
  21. "errors"
  22. )
  23. var defaultIV = []byte{0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}
  24. // KeyWrap implements NIST key wrapping; it wraps a content encryption key (cek) with the given block cipher.
  25. func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) {
  26. if len(cek)%8 != 0 {
  27. return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
  28. }
  29. n := len(cek) / 8
  30. r := make([][]byte, n)
  31. for i := range r {
  32. r[i] = make([]byte, 8)
  33. copy(r[i], cek[i*8:])
  34. }
  35. buffer := make([]byte, 16)
  36. tBytes := make([]byte, 8)
  37. copy(buffer, defaultIV)
  38. for t := 0; t < 6*n; t++ {
  39. copy(buffer[8:], r[t%n])
  40. block.Encrypt(buffer, buffer)
  41. binary.BigEndian.PutUint64(tBytes, uint64(t+1))
  42. for i := 0; i < 8; i++ {
  43. buffer[i] = buffer[i] ^ tBytes[i]
  44. }
  45. copy(r[t%n], buffer[8:])
  46. }
  47. out := make([]byte, (n+1)*8)
  48. copy(out, buffer[:8])
  49. for i := range r {
  50. copy(out[(i+1)*8:], r[i])
  51. }
  52. return out, nil
  53. }
  54. // KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher.
  55. func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) {
  56. if len(ciphertext)%8 != 0 {
  57. return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
  58. }
  59. n := (len(ciphertext) / 8) - 1
  60. r := make([][]byte, n)
  61. for i := range r {
  62. r[i] = make([]byte, 8)
  63. copy(r[i], ciphertext[(i+1)*8:])
  64. }
  65. buffer := make([]byte, 16)
  66. tBytes := make([]byte, 8)
  67. copy(buffer[:8], ciphertext[:8])
  68. for t := 6*n - 1; t >= 0; t-- {
  69. binary.BigEndian.PutUint64(tBytes, uint64(t+1))
  70. for i := 0; i < 8; i++ {
  71. buffer[i] = buffer[i] ^ tBytes[i]
  72. }
  73. copy(buffer[8:], r[t%n])
  74. block.Decrypt(buffer, buffer)
  75. copy(r[t%n], buffer[8:])
  76. }
  77. if subtle.ConstantTimeCompare(buffer[:8], defaultIV) == 0 {
  78. return nil, errors.New("square/go-jose: failed to unwrap key")
  79. }
  80. out := make([]byte, n*8)
  81. for i := range r {
  82. copy(out[i*8:], r[i])
  83. }
  84. return out, nil
  85. }