...

Source file src/gopkg.in/square/go-jose.v2/cipher/key_wrap.go

Documentation: gopkg.in/square/go-jose.v2/cipher

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

View as plain text