123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- /*-
- * Copyright 2014 Square Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package josecipher
- import (
- "crypto/cipher"
- "crypto/subtle"
- "encoding/binary"
- "errors"
- )
- var defaultIV = []byte{0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}
- // KeyWrap implements NIST key wrapping; it wraps a content encryption key (cek) with the given block cipher.
- func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) {
- if len(cek)%8 != 0 {
- return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
- }
- n := len(cek) / 8
- r := make([][]byte, n)
- for i := range r {
- r[i] = make([]byte, 8)
- copy(r[i], cek[i*8:])
- }
- buffer := make([]byte, 16)
- tBytes := make([]byte, 8)
- copy(buffer, defaultIV)
- for t := 0; t < 6*n; t++ {
- copy(buffer[8:], r[t%n])
- block.Encrypt(buffer, buffer)
- binary.BigEndian.PutUint64(tBytes, uint64(t+1))
- for i := 0; i < 8; i++ {
- buffer[i] = buffer[i] ^ tBytes[i]
- }
- copy(r[t%n], buffer[8:])
- }
- out := make([]byte, (n+1)*8)
- copy(out, buffer[:8])
- for i := range r {
- copy(out[(i+1)*8:], r[i])
- }
- return out, nil
- }
- // KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher.
- func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) {
- if len(ciphertext)%8 != 0 {
- return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
- }
- n := (len(ciphertext) / 8) - 1
- r := make([][]byte, n)
- for i := range r {
- r[i] = make([]byte, 8)
- copy(r[i], ciphertext[(i+1)*8:])
- }
- buffer := make([]byte, 16)
- tBytes := make([]byte, 8)
- copy(buffer[:8], ciphertext[:8])
- for t := 6*n - 1; t >= 0; t-- {
- binary.BigEndian.PutUint64(tBytes, uint64(t+1))
- for i := 0; i < 8; i++ {
- buffer[i] = buffer[i] ^ tBytes[i]
- }
- copy(buffer[8:], r[t%n])
- block.Decrypt(buffer, buffer)
- copy(r[t%n], buffer[8:])
- }
- if subtle.ConstantTimeCompare(buffer[:8], defaultIV) == 0 {
- return nil, errors.New("square/go-jose: failed to unwrap key")
- }
- out := make([]byte, n*8)
- for i := range r {
- copy(out[i*8:], r[i])
- }
- return out, nil
- }
|