diff --git a/Makefile b/Makefile index 17976610..67e9b9b7 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,11 @@ +GOFLAGS ?= -mod=vendor + test: @echo "go test -mod vendor ./..." - @go test -mod vendor ./... \ No newline at end of file + @go test ./... + +refresh-deps: + @echo "go mod tidy" + @GOFLAGS='' GONOSUMDB=github.com/hyperledger/fabric go mod tidy + @echo "go mod vendor" + @GOFLAGS='' GONOSUMDB=github.com/hyperledger/fabric go mod vendor \ No newline at end of file diff --git a/extensions/encryption/aes.go b/extensions/encryption/aes.go new file mode 100644 index 00000000..ebc7207e --- /dev/null +++ b/extensions/encryption/aes.go @@ -0,0 +1,126 @@ +package encryption + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" + + "github.com/pkg/errors" +) + +// From bccsp/sw/aes +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 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 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 +} + +// 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 +} + +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 +} + +func EncryptBytes(key, value []byte) ([]byte, error) { + // IV temporary blank + return aesCBCEncryptWithIV(make([]byte, 16), key, pkcs7Padding(value)) +} + +func DecryptBytes(key, value []byte) ([]byte, error) { + return AESCBCPKCS7Decrypt(key, value) +} diff --git a/extensions/encryption/encryption.go b/extensions/encryption/encryption.go index c4398199..d97cc786 100644 --- a/extensions/encryption/encryption.go +++ b/extensions/encryption/encryption.go @@ -1,8 +1,6 @@ package encryption import ( - "github.com/hyperledger/fabric/bccsp/factory" - "github.com/hyperledger/fabric/core/chaincode/shim/ext/entities" "github.com/pkg/errors" "github.com/s7techlab/cckit/convert" "github.com/s7techlab/cckit/router" @@ -10,12 +8,6 @@ import ( const TransientMapKey = `ENCODE_KEY` -func init() { - if err := factory.InitFactories(nil); err != nil { - panic(err) - } -} - // EncryptArgs convert args to [][]byte and encrypt args with key func EncryptArgs(key []byte, args ...interface{}) ([][]byte, error) { argBytes, err := convert.ArgsToBytes(args...) @@ -30,7 +22,7 @@ func EncryptArgs(key []byte, args ...interface{}) ([][]byte, error) { func EncryptArgsBytes(key []byte, argsBytes [][]byte) ([][]byte, error) { eargs := make([][]byte, len(argsBytes)) for i, bb := range argsBytes { - encrypted, err := Encrypt(key, bb) + encrypted, err := EncryptBytes(key, bb) if err != nil { return nil, errors.Wrap(err, `encryption error`) } @@ -51,7 +43,7 @@ func DecryptArgs(key []byte, args [][]byte) ([][]byte, error) { continue } - decrypted, err := Decrypt(key, a) + decrypted, err := DecryptBytes(key, a) if err != nil { return nil, errors.Wrap(err, `decryption error`) } @@ -63,28 +55,20 @@ func DecryptArgs(key []byte, args [][]byte) ([][]byte, error) { // Encrypt converts value to []byte and encrypts its with key func Encrypt(key []byte, value interface{}) ([]byte, error) { // TODO: customize IV - encrypter, err := entities.NewAES256EncrypterEntity("ID", factory.GetDefault(), key, make([]byte, 16)) - if err != nil { - return nil, err - } - bb, err := convert.ToBytes(value) if err != nil { return nil, errors.Wrap(err, `convert values to bytes`) } - return encrypter.Encrypt(bb) + return EncryptBytes(key, bb) } // Decrypt decrypts value with key func Decrypt(key, value []byte) ([]byte, error) { - encrypter, err := entities.NewAES256EncrypterEntity("ID", factory.GetDefault(), key, nil) - if err != nil { - return nil, err - } + bb := make([]byte, len(value)) copy(bb, value) - return encrypter.Decrypt(bb) + return DecryptBytes(key, bb) } // TransientMapWithKey creates transient map with encrypting/decrypting key diff --git a/go.mod b/go.mod index 94b50e22..4b852cf7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/golang/protobuf v1.3.1 github.com/grpc-ecosystem/grpc-gateway v1.9.0 github.com/hyperledger/fabric v1.4.4 - github.com/hyperledger/fabric-amcl v0.0.0-20181230093703-5ccba6eab8d6 // indirect github.com/hyperledger/fabric-lib-go v1.0.0 // indirect github.com/miekg/pkcs11 v1.0.2 // indirect github.com/mwitkow/go-proto-validators v0.0.0-20190212092829-1f388280e944 diff --git a/state/mapping/mapping_test.go b/state/mapping/mapping_test.go index 5f76f668..7553e9d4 100644 --- a/state/mapping/mapping_test.go +++ b/state/mapping/mapping_test.go @@ -7,7 +7,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/gogo/protobuf/proto" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric/protos/peer" identitytestdata "github.com/s7techlab/cckit/identity/testdata"