github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/bccsp/sw/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 sw
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/aes"
    22  	"crypto/cipher"
    23  	"crypto/rand"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  )
    28  
    29  // GetRandomBytes returns len random looking bytes
    30  func GetRandomBytes(len int) ([]byte, error) {
    31  	buffer := make([]byte, len)
    32  
    33  	n, err := rand.Read(buffer)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	if n != len {
    38  		return nil, fmt.Errorf("Buffer not filled. Requested [%d], got [%d]", len, n)
    39  	}
    40  
    41  	return buffer, nil
    42  }
    43  
    44  func pkcs7Padding(src []byte) []byte {
    45  	padding := aes.BlockSize - len(src)%aes.BlockSize
    46  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    47  	return append(src, padtext...)
    48  }
    49  
    50  func pkcs7UnPadding(src []byte) ([]byte, error) {
    51  	length := len(src)
    52  	unpadding := int(src[length-1])
    53  
    54  	if unpadding > aes.BlockSize || unpadding == 0 {
    55  		return nil, errors.New("Invalid pkcs7 padding (unpadding > aes.BlockSize || unpadding == 0)")
    56  	}
    57  
    58  	pad := src[len(src)-unpadding:]
    59  	for i := 0; i < unpadding; i++ {
    60  		if pad[i] != byte(unpadding) {
    61  			return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)")
    62  		}
    63  	}
    64  
    65  	return src[:(length - unpadding)], nil
    66  }
    67  
    68  func aesCBCEncrypt(key, s []byte) ([]byte, error) {
    69  	if len(s)%aes.BlockSize != 0 {
    70  		return nil, errors.New("Invalid plaintext. It must be a multiple of the block size")
    71  	}
    72  
    73  	block, err := aes.NewCipher(key)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	ciphertext := make([]byte, aes.BlockSize+len(s))
    79  	iv := ciphertext[:aes.BlockSize]
    80  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	mode := cipher.NewCBCEncrypter(block, iv)
    85  	mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
    86  
    87  	return ciphertext, nil
    88  }
    89  
    90  func aesCBCDecrypt(key, src []byte) ([]byte, error) {
    91  	block, err := aes.NewCipher(key)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	if len(src) < aes.BlockSize {
    97  		return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
    98  	}
    99  	iv := src[:aes.BlockSize]
   100  	src = src[aes.BlockSize:]
   101  
   102  	if len(src)%aes.BlockSize != 0 {
   103  		return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
   104  	}
   105  
   106  	mode := cipher.NewCBCDecrypter(block, iv)
   107  
   108  	mode.CryptBlocks(src, src)
   109  
   110  	return src, nil
   111  }
   112  
   113  // AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding
   114  func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
   115  	// First pad
   116  	tmp := pkcs7Padding(src)
   117  
   118  	// Then encrypt
   119  	return aesCBCEncrypt(key, tmp)
   120  }
   121  
   122  // AESCBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding
   123  func AESCBCPKCS7Decrypt(key, src []byte) ([]byte, error) {
   124  	// First decrypt
   125  	pt, err := aesCBCDecrypt(key, src)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	// Then remove padding
   131  	original, err := pkcs7UnPadding(pt)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	return original, nil
   137  }