222 lines
5.8 KiB
Go
222 lines
5.8 KiB
Go
/*
|
|
Copyright IBM Corp. 2016 All Rights Reserved.
|
|
|
|
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 sw
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/hyperledger/fabric/bccsp"
|
|
)
|
|
|
|
// GetRandomBytes returns len random looking bytes
|
|
func GetRandomBytes(len int) ([]byte, error) {
|
|
if len < 0 {
|
|
return nil, errors.New("Len must be larger than 0")
|
|
}
|
|
|
|
buffer := make([]byte, len)
|
|
|
|
n, err := rand.Read(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if n != len {
|
|
return nil, fmt.Errorf("Buffer not filled. Requested [%d], got [%d]", len, n)
|
|
}
|
|
|
|
return buffer, nil
|
|
}
|
|
|
|
func pkcs7Padding(src []byte) []byte {
|
|
padding := aes.BlockSize - len(src)%aes.BlockSize
|
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
|
return append(src, padtext...)
|
|
}
|
|
|
|
func pkcs7UnPadding(src []byte) ([]byte, error) {
|
|
length := len(src)
|
|
unpadding := int(src[length-1])
|
|
|
|
if unpadding > aes.BlockSize || unpadding == 0 {
|
|
return nil, errors.New("Invalid pkcs7 padding (unpadding > aes.BlockSize || unpadding == 0)")
|
|
}
|
|
|
|
pad := src[len(src)-unpadding:]
|
|
for i := 0; i < unpadding; i++ {
|
|
if pad[i] != byte(unpadding) {
|
|
return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)")
|
|
}
|
|
}
|
|
|
|
return src[:(length - unpadding)], nil
|
|
}
|
|
|
|
func aesCBCEncrypt(key, s []byte) ([]byte, error) {
|
|
return aesCBCEncryptWithRand(rand.Reader, key, s)
|
|
}
|
|
|
|
func aesCBCEncryptWithRand(prng io.Reader, key, s []byte) ([]byte, error) {
|
|
if len(s)%aes.BlockSize != 0 {
|
|
return nil, errors.New("Invalid plaintext. It must be a multiple of the block size")
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ciphertext := make([]byte, aes.BlockSize+len(s))
|
|
iv := ciphertext[:aes.BlockSize]
|
|
if _, err := io.ReadFull(prng, iv); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mode := cipher.NewCBCEncrypter(block, iv)
|
|
mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
|
|
|
|
return ciphertext, nil
|
|
}
|
|
|
|
func aesCBCEncryptWithIV(IV []byte, key, s []byte) ([]byte, error) {
|
|
if len(s)%aes.BlockSize != 0 {
|
|
return nil, errors.New("Invalid plaintext. It must be a multiple of the block size")
|
|
}
|
|
|
|
if len(IV) != aes.BlockSize {
|
|
return nil, errors.New("Invalid IV. It must have length the block size")
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ciphertext := make([]byte, aes.BlockSize+len(s))
|
|
copy(ciphertext[:aes.BlockSize], IV)
|
|
|
|
mode := cipher.NewCBCEncrypter(block, IV)
|
|
mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
|
|
|
|
return ciphertext, nil
|
|
}
|
|
|
|
func aesCBCDecrypt(key, src []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(src) < aes.BlockSize {
|
|
return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
|
|
}
|
|
iv := src[:aes.BlockSize]
|
|
src = src[aes.BlockSize:]
|
|
|
|
if len(src)%aes.BlockSize != 0 {
|
|
return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
|
|
}
|
|
|
|
mode := cipher.NewCBCDecrypter(block, iv)
|
|
|
|
mode.CryptBlocks(src, src)
|
|
|
|
return src, nil
|
|
}
|
|
|
|
// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding
|
|
func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
|
|
// First pad
|
|
tmp := pkcs7Padding(src)
|
|
|
|
// Then encrypt
|
|
return aesCBCEncrypt(key, tmp)
|
|
}
|
|
|
|
// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding using as prng the passed to the function
|
|
func AESCBCPKCS7EncryptWithRand(prng io.Reader, key, src []byte) ([]byte, error) {
|
|
// First pad
|
|
tmp := pkcs7Padding(src)
|
|
|
|
// Then encrypt
|
|
return aesCBCEncryptWithRand(prng, key, tmp)
|
|
}
|
|
|
|
// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding, the IV used is the one passed to the function
|
|
func AESCBCPKCS7EncryptWithIV(IV []byte, key, src []byte) ([]byte, error) {
|
|
// First pad
|
|
tmp := pkcs7Padding(src)
|
|
|
|
// Then encrypt
|
|
return aesCBCEncryptWithIV(IV, key, tmp)
|
|
}
|
|
|
|
// AESCBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding
|
|
func AESCBCPKCS7Decrypt(key, src []byte) ([]byte, error) {
|
|
// First decrypt
|
|
pt, err := aesCBCDecrypt(key, src)
|
|
if err == nil {
|
|
return pkcs7UnPadding(pt)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
type aescbcpkcs7Encryptor struct{}
|
|
|
|
func (e *aescbcpkcs7Encryptor) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
|
|
switch o := opts.(type) {
|
|
case *bccsp.AESCBCPKCS7ModeOpts:
|
|
// AES in CBC mode with PKCS7 padding
|
|
|
|
if len(o.IV) != 0 && o.PRNG != nil {
|
|
return nil, errors.New("Invalid options. Either IV or PRNG should be different from nil, or both nil.")
|
|
}
|
|
|
|
if len(o.IV) != 0 {
|
|
// Encrypt with the passed IV
|
|
return AESCBCPKCS7EncryptWithIV(o.IV, k.(*aesPrivateKey).privKey, plaintext)
|
|
} else if o.PRNG != nil {
|
|
// Encrypt with PRNG
|
|
return AESCBCPKCS7EncryptWithRand(o.PRNG, k.(*aesPrivateKey).privKey, plaintext)
|
|
}
|
|
// AES in CBC mode with PKCS7 padding
|
|
return AESCBCPKCS7Encrypt(k.(*aesPrivateKey).privKey, plaintext)
|
|
case bccsp.AESCBCPKCS7ModeOpts:
|
|
return e.Encrypt(k, plaintext, &o)
|
|
default:
|
|
return nil, fmt.Errorf("Mode not recognized [%s]", opts)
|
|
}
|
|
}
|
|
|
|
type aescbcpkcs7Decryptor struct{}
|
|
|
|
func (*aescbcpkcs7Decryptor) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) {
|
|
// check for mode
|
|
switch opts.(type) {
|
|
case *bccsp.AESCBCPKCS7ModeOpts, bccsp.AESCBCPKCS7ModeOpts:
|
|
// AES in CBC mode with PKCS7 padding
|
|
return AESCBCPKCS7Decrypt(k.(*aesPrivateKey).privKey, ciphertext)
|
|
default:
|
|
return nil, fmt.Errorf("Mode not recognized [%s]", opts)
|
|
}
|
|
}
|