github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/accesscontrol/crypto/utils/aes.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     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 utils
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/aes"
    22  	"crypto/cipher"
    23  	"crypto/rand"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  
    28  	"github.com/hyperledger/fabric/core/crypto/primitives"
    29  )
    30  
    31  const (
    32  	// AESKeyLength is the default AES key length
    33  	AESKeyLength = 32
    34  
    35  	// NonceSize is the default NonceSize
    36  	NonceSize = 24
    37  )
    38  
    39  // GenAESKey returns a random AES key of length AESKeyLength
    40  func GenAESKey() ([]byte, error) {
    41  	return primitives.GetRandomBytes(AESKeyLength)
    42  }
    43  
    44  // PKCS7Padding pads as prescribed by the PKCS7 standard
    45  func PKCS7Padding(src []byte) []byte {
    46  	padding := aes.BlockSize - len(src)%aes.BlockSize
    47  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    48  	return append(src, padtext...)
    49  }
    50  
    51  // PKCS7UnPadding unpads as prescribed by the PKCS7 standard
    52  func PKCS7UnPadding(src []byte) ([]byte, error) {
    53  	length := len(src)
    54  	unpadding := int(src[length-1])
    55  
    56  	if unpadding > aes.BlockSize || unpadding == 0 {
    57  		return nil, fmt.Errorf("invalid padding")
    58  	}
    59  
    60  	pad := src[len(src)-unpadding:]
    61  	for i := 0; i < unpadding; i++ {
    62  		if pad[i] != byte(unpadding) {
    63  			return nil, fmt.Errorf("invalid padding")
    64  		}
    65  	}
    66  
    67  	return src[:(length - unpadding)], nil
    68  }
    69  
    70  // CBCEncrypt encrypts using CBC mode
    71  func CBCEncrypt(key, s []byte) ([]byte, error) {
    72  	// CBC mode works on blocks so plaintexts may need to be padded to the
    73  	// next whole block. For an example of such padding, see
    74  	// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
    75  	// assume that the plaintext is already of the correct length.
    76  	if len(s)%aes.BlockSize != 0 {
    77  		return nil, errors.New("plaintext is not a multiple of the block size")
    78  	}
    79  
    80  	block, err := aes.NewCipher(key)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	// The IV needs to be unique, but not secure. Therefore it's common to
    86  	// include it at the beginning of the ciphertext.
    87  	ciphertext := make([]byte, aes.BlockSize+len(s))
    88  	iv := ciphertext[:aes.BlockSize]
    89  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	mode := cipher.NewCBCEncrypter(block, iv)
    94  	mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
    95  
    96  	// It's important to remember that ciphertexts must be authenticated
    97  	// (i.e. by using crypto/hmac) as well as being encrypted in order to
    98  	// be secure.
    99  	return ciphertext, nil
   100  }
   101  
   102  // CBCDecrypt decrypts using CBC mode
   103  func CBCDecrypt(key, src []byte) ([]byte, error) {
   104  	block, err := aes.NewCipher(key)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	// The IV needs to be unique, but not secure. Therefore it's common to
   110  	// include it at the beginning of the ciphertext.
   111  	if len(src) < aes.BlockSize {
   112  		return nil, errors.New("ciphertext too short")
   113  	}
   114  	iv := src[:aes.BlockSize]
   115  	src = src[aes.BlockSize:]
   116  
   117  	// CBC mode always works in whole blocks.
   118  	if len(src)%aes.BlockSize != 0 {
   119  		return nil, errors.New("ciphertext is not a multiple of the block size")
   120  	}
   121  
   122  	mode := cipher.NewCBCDecrypter(block, iv)
   123  
   124  	// CryptBlocks can work in-place if the two arguments are the same.
   125  	mode.CryptBlocks(src, src)
   126  
   127  	// If the original plaintext lengths are not a multiple of the block
   128  	// size, padding would have to be added when encrypting, which would be
   129  	// removed at this point. For an example, see
   130  	// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
   131  	// critical to note that ciphertexts must be authenticated (i.e. by
   132  	// using crypto/hmac) before being decrypted in order to avoid creating
   133  	// a padding oracle.
   134  
   135  	return src, nil
   136  }
   137  
   138  // CBCPKCS7Encrypt combines CBC encryption and PKCS7 padding
   139  func CBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
   140  	return CBCEncrypt(key, PKCS7Padding(src))
   141  }
   142  
   143  // CBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding
   144  func CBCPKCS7Decrypt(key, src []byte) ([]byte, error) {
   145  	pt, err := CBCDecrypt(key, src)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	original, err := PKCS7UnPadding(pt)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	return original, nil
   156  }