412 lines
12 KiB
Go
412 lines
12 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 idemix
|
|
|
|
import (
|
|
"hash"
|
|
"reflect"
|
|
|
|
bccsp "github.com/IBM/idemix/bccsp/schemes"
|
|
"github.com/IBM/idemix/common/flogging"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var (
|
|
logger = flogging.MustGetLogger("bccsp_idemix")
|
|
)
|
|
|
|
// KeyGenerator is a BCCSP-like interface that provides key generation algorithms
|
|
type KeyGenerator interface {
|
|
|
|
// KeyGen generates a key using opts.
|
|
KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error)
|
|
}
|
|
|
|
// KeyDeriver is a BCCSP-like interface that provides key derivation algorithms
|
|
type KeyDeriver interface {
|
|
|
|
// KeyDeriv derives a key from k using opts.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error)
|
|
}
|
|
|
|
// KeyImporter is a BCCSP-like interface that provides key import algorithms
|
|
type KeyImporter interface {
|
|
|
|
// KeyImport imports a key from its raw representation using opts.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error)
|
|
}
|
|
|
|
// Encryptor is a BCCSP-like interface that provides encryption algorithms
|
|
type Encryptor interface {
|
|
|
|
// Encrypt encrypts plaintext using key k.
|
|
// The opts argument should be appropriate for the algorithm used.
|
|
Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error)
|
|
}
|
|
|
|
// Decryptor is a BCCSP-like interface that provides decryption algorithms
|
|
type Decryptor interface {
|
|
|
|
// Decrypt decrypts ciphertext using key k.
|
|
// The opts argument should be appropriate for the algorithm used.
|
|
Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error)
|
|
}
|
|
|
|
// Signer is a BCCSP-like interface that provides signing algorithms
|
|
type Signer interface {
|
|
|
|
// Sign signs digest using key k.
|
|
// The opts argument should be appropriate for the algorithm used.
|
|
//
|
|
// Note that when a signature of a hash of a larger message is needed,
|
|
// the caller is responsible for hashing the larger message and passing
|
|
// the hash (as digest).
|
|
Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error)
|
|
}
|
|
|
|
// Verifier is a BCCSP-like interface that provides verifying algorithms
|
|
type Verifier interface {
|
|
|
|
// Verify verifies signature against key k and digest
|
|
// The opts argument should be appropriate for the algorithm used.
|
|
Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error)
|
|
}
|
|
|
|
// Hasher is a BCCSP-like interface that provides hash algorithms
|
|
type Hasher interface {
|
|
|
|
// Hash hashes messages msg using options opts.
|
|
// If opts is nil, the default hash function will be used.
|
|
Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error)
|
|
|
|
// GetHash returns and instance of hash.Hash using options opts.
|
|
// If opts is nil, the default hash function will be returned.
|
|
GetHash(opts bccsp.HashOpts) (h hash.Hash, err error)
|
|
}
|
|
|
|
// CSP provides a generic implementation of the BCCSP interface based
|
|
// on wrappers. It can be customized by providing implementations for the
|
|
// following algorithm-based wrappers: KeyGenerator, KeyDeriver, KeyImporter,
|
|
// Encryptor, Decryptor, Signer, Verifier, Hasher. Each wrapper is bound to a
|
|
// goland type representing either an option or a key.
|
|
type CSP struct {
|
|
ks bccsp.KeyStore
|
|
|
|
KeyGenerators map[reflect.Type]KeyGenerator
|
|
KeyDerivers map[reflect.Type]KeyDeriver
|
|
KeyImporters map[reflect.Type]KeyImporter
|
|
Encryptors map[reflect.Type]Encryptor
|
|
Decryptors map[reflect.Type]Decryptor
|
|
Signers map[reflect.Type]Signer
|
|
Verifiers map[reflect.Type]Verifier
|
|
Hashers map[reflect.Type]Hasher
|
|
}
|
|
|
|
func NewImpl(keyStore bccsp.KeyStore) (*CSP, error) {
|
|
if keyStore == nil {
|
|
return nil, errors.Errorf("Invalid bccsp.KeyStore instance. It must be different from nil.")
|
|
}
|
|
|
|
encryptors := make(map[reflect.Type]Encryptor)
|
|
decryptors := make(map[reflect.Type]Decryptor)
|
|
signers := make(map[reflect.Type]Signer)
|
|
verifiers := make(map[reflect.Type]Verifier)
|
|
hashers := make(map[reflect.Type]Hasher)
|
|
keyGenerators := make(map[reflect.Type]KeyGenerator)
|
|
keyDerivers := make(map[reflect.Type]KeyDeriver)
|
|
keyImporters := make(map[reflect.Type]KeyImporter)
|
|
|
|
csp := &CSP{keyStore,
|
|
keyGenerators, keyDerivers, keyImporters, encryptors,
|
|
decryptors, signers, verifiers, hashers}
|
|
|
|
return csp, nil
|
|
}
|
|
|
|
// KeyGen generates a key using opts.
|
|
func (csp *CSP) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
|
|
// Validate arguments
|
|
if opts == nil {
|
|
return nil, errors.New("Invalid Opts parameter. It must not be nil.")
|
|
}
|
|
|
|
keyGenerator, found := csp.KeyGenerators[reflect.TypeOf(opts)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'KeyGenOpts' provided [%v]", opts)
|
|
}
|
|
|
|
k, err = keyGenerator.KeyGen(opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed generating key with opts [%v]", opts)
|
|
}
|
|
|
|
// If the key is not Ephemeral, store it.
|
|
if !opts.Ephemeral() {
|
|
// Store the key
|
|
err = csp.ks.StoreKey(k)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed storing key [%s]", opts.Algorithm())
|
|
}
|
|
}
|
|
|
|
return k, nil
|
|
}
|
|
|
|
// KeyDeriv derives a key from k using opts.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
func (csp *CSP) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) {
|
|
// Validate arguments
|
|
if k == nil {
|
|
return nil, errors.New("Invalid Key. It must not be nil.")
|
|
}
|
|
if opts == nil {
|
|
return nil, errors.New("Invalid opts. It must not be nil.")
|
|
}
|
|
|
|
keyDeriver, found := csp.KeyDerivers[reflect.TypeOf(k)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'Key' provided [%v]", k)
|
|
}
|
|
|
|
k, err = keyDeriver.KeyDeriv(k, opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed deriving key with opts [%v]", opts)
|
|
}
|
|
|
|
// If the key is not Ephemeral, store it.
|
|
if !opts.Ephemeral() {
|
|
// Store the key
|
|
err = csp.ks.StoreKey(k)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed storing key [%s]", opts.Algorithm())
|
|
}
|
|
}
|
|
|
|
return k, nil
|
|
}
|
|
|
|
// KeyImport imports a key from its raw representation using opts.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
func (csp *CSP) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
|
|
// Validate arguments
|
|
if raw == nil {
|
|
return nil, errors.New("Invalid raw. It must not be nil.")
|
|
}
|
|
if opts == nil {
|
|
return nil, errors.New("Invalid opts. It must not be nil.")
|
|
}
|
|
|
|
keyImporter, found := csp.KeyImporters[reflect.TypeOf(opts)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'KeyImportOpts' provided [%v]", opts)
|
|
}
|
|
|
|
k, err = keyImporter.KeyImport(raw, opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed importing key with opts [%v]", opts)
|
|
}
|
|
|
|
// If the key is not Ephemeral, store it.
|
|
if !opts.Ephemeral() {
|
|
// Store the key
|
|
err = csp.ks.StoreKey(k)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed storing imported key with opts [%v]", opts)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// GetKey returns the key this CSP associates to
|
|
// the Subject Key Identifier ski.
|
|
func (csp *CSP) GetKey(ski []byte) (k bccsp.Key, err error) {
|
|
k, err = csp.ks.GetKey(ski)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed getting key for SKI [%v]", ski)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Hash hashes messages msg using options opts.
|
|
func (csp *CSP) Hash(msg []byte, opts bccsp.HashOpts) (digest []byte, err error) {
|
|
// Validate arguments
|
|
if opts == nil {
|
|
return nil, errors.New("Invalid opts. It must not be nil.")
|
|
}
|
|
|
|
hasher, found := csp.Hashers[reflect.TypeOf(opts)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'HashOpt' provided [%v]", opts)
|
|
}
|
|
|
|
digest, err = hasher.Hash(msg, opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed hashing with opts [%v]", opts)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// GetHash returns and instance of hash.Hash using options opts.
|
|
// If opts is nil then the default hash function is returned.
|
|
func (csp *CSP) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) {
|
|
// Validate arguments
|
|
if opts == nil {
|
|
return nil, errors.New("Invalid opts. It must not be nil.")
|
|
}
|
|
|
|
hasher, found := csp.Hashers[reflect.TypeOf(opts)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'HashOpt' provided [%v]", opts)
|
|
}
|
|
|
|
h, err = hasher.GetHash(opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed getting hash function with opts [%v]", opts)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Sign signs digest using key k.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
//
|
|
// Note that when a signature of a hash of a larger message is needed,
|
|
// the caller is responsible for hashing the larger message and passing
|
|
// the hash (as digest).
|
|
func (csp *CSP) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) {
|
|
// Validate arguments
|
|
if k == nil {
|
|
return nil, errors.New("Invalid Key. It must not be nil.")
|
|
}
|
|
if len(digest) == 0 {
|
|
return nil, errors.New("Invalid digest. Cannot be empty.")
|
|
}
|
|
|
|
keyType := reflect.TypeOf(k)
|
|
signer, found := csp.Signers[keyType]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'SignKey' provided [%s]", keyType)
|
|
}
|
|
|
|
signature, err = signer.Sign(k, digest, opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed signing with opts [%v]", opts)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Verify verifies signature against key k and digest
|
|
func (csp *CSP) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) {
|
|
// Validate arguments
|
|
if k == nil {
|
|
return false, errors.New("Invalid Key. It must not be nil.")
|
|
}
|
|
if len(signature) == 0 {
|
|
return false, errors.New("Invalid signature. Cannot be empty.")
|
|
}
|
|
if len(digest) == 0 {
|
|
return false, errors.New("Invalid digest. Cannot be empty.")
|
|
}
|
|
|
|
verifier, found := csp.Verifiers[reflect.TypeOf(k)]
|
|
if !found {
|
|
return false, errors.Errorf("Unsupported 'VerifyKey' provided [%v]", k)
|
|
}
|
|
|
|
valid, err = verifier.Verify(k, signature, digest, opts)
|
|
if err != nil {
|
|
return false, errors.Wrapf(err, "Failed verifing with opts [%v]", opts)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Encrypt encrypts plaintext using key k.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
func (csp *CSP) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
|
|
// Validate arguments
|
|
if k == nil {
|
|
return nil, errors.New("Invalid Key. It must not be nil.")
|
|
}
|
|
|
|
encryptor, found := csp.Encryptors[reflect.TypeOf(k)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'EncryptKey' provided [%v]", k)
|
|
}
|
|
|
|
return encryptor.Encrypt(k, plaintext, opts)
|
|
}
|
|
|
|
// Decrypt decrypts ciphertext using key k.
|
|
// The opts argument should be appropriate for the primitive used.
|
|
func (csp *CSP) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) {
|
|
// Validate arguments
|
|
if k == nil {
|
|
return nil, errors.New("Invalid Key. It must not be nil.")
|
|
}
|
|
|
|
decryptor, found := csp.Decryptors[reflect.TypeOf(k)]
|
|
if !found {
|
|
return nil, errors.Errorf("Unsupported 'DecryptKey' provided [%v]", k)
|
|
}
|
|
|
|
plaintext, err = decryptor.Decrypt(k, ciphertext, opts)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Failed decrypting with opts [%v]", opts)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// AddWrapper binds the passed type to the passed wrapper.
|
|
// Notice that that wrapper must be an instance of one of the following interfaces:
|
|
// KeyGenerator, KeyDeriver, KeyImporter, Encryptor, Decryptor, Signer, Verifier, Hasher.
|
|
func (csp *CSP) AddWrapper(t reflect.Type, w interface{}) error {
|
|
if t == nil {
|
|
return errors.Errorf("type cannot be nil")
|
|
}
|
|
if w == nil {
|
|
return errors.Errorf("wrapper cannot be nil")
|
|
}
|
|
switch dt := w.(type) {
|
|
case KeyGenerator:
|
|
csp.KeyGenerators[t] = dt
|
|
case KeyImporter:
|
|
csp.KeyImporters[t] = dt
|
|
case KeyDeriver:
|
|
csp.KeyDerivers[t] = dt
|
|
case Encryptor:
|
|
csp.Encryptors[t] = dt
|
|
case Decryptor:
|
|
csp.Decryptors[t] = dt
|
|
case Signer:
|
|
csp.Signers[t] = dt
|
|
case Verifier:
|
|
csp.Verifiers[t] = dt
|
|
case Hasher:
|
|
csp.Hashers[t] = dt
|
|
default:
|
|
return errors.Errorf("wrapper type not valid, must be on of: KeyGenerator, KeyDeriver, KeyImporter, Encryptor, Decryptor, Signer, Verifier, Hasher")
|
|
}
|
|
return nil
|
|
}
|