...

Source file src/github.com/ThalesIgnite/crypto11/aead.go

Documentation: github.com/ThalesIgnite/crypto11

     1  // Copyright 2018 Thales e-Security, Inc
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining
     4  // a copy of this software and associated documentation files (the
     5  // "Software"), to deal in the Software without restriction, including
     6  // without limitation the rights to use, copy, modify, merge, publish,
     7  // distribute, sublicense, and/or sell copies of the Software, and to
     8  // permit persons to whom the Software is furnished to do so, subject to
     9  // the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be
    12  // included in all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    17  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    18  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    19  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    20  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package crypto11
    23  
    24  import (
    25  	"crypto/cipher"
    26  	"errors"
    27  	"fmt"
    28  
    29  	"github.com/miekg/pkcs11"
    30  )
    31  
    32  // cipher.AEAD ----------------------------------------------------------
    33  
    34  // A PaddingMode is used by a block cipher (see NewCBC).
    35  type PaddingMode int
    36  
    37  const (
    38  	// PaddingNone represents a block cipher with no padding.
    39  	PaddingNone PaddingMode = iota
    40  
    41  	// PaddingPKCS represents a block cipher used with PKCS#7 padding.
    42  	PaddingPKCS
    43  )
    44  
    45  var errBadGCMNonceSize = errors.New("nonce slice too small to hold IV")
    46  
    47  type genericAead struct {
    48  	key *SecretKey
    49  
    50  	overhead int
    51  
    52  	nonceSize int
    53  
    54  	// Note - if the GCMParams result is non-nil, the caller must call Free() on the params when
    55  	// finished.
    56  	makeMech func(nonce []byte, additionalData []byte, encrypt bool) ([]*pkcs11.Mechanism, *pkcs11.GCMParams, error)
    57  }
    58  
    59  // NewGCM returns a given cipher wrapped in Galois Counter Mode, with the standard
    60  // nonce length.
    61  //
    62  // This depends on the HSM supporting the CKM_*_GCM mechanism. If it is not supported
    63  // then you must use cipher.NewGCM; it will be slow.
    64  func (key *SecretKey) NewGCM() (cipher.AEAD, error) {
    65  	if key.Cipher.GCMMech == 0 {
    66  		return nil, fmt.Errorf("GCM not implemented for key type %#x", key.Cipher.GenParams[0].KeyType)
    67  	}
    68  
    69  	g := genericAead{
    70  		key:       key,
    71  		overhead:  16,
    72  		nonceSize: key.context.cfg.GCMIVLength,
    73  		makeMech: func(nonce []byte, additionalData []byte, encrypt bool) ([]*pkcs11.Mechanism, *pkcs11.GCMParams, error) {
    74  			var params *pkcs11.GCMParams
    75  
    76  			if (encrypt && key.context.cfg.UseGCMIVFromHSM &&
    77  				!key.context.cfg.GCMIVFromHSMControl.SupplyIvForHSMGCMEncrypt) || (!encrypt &&
    78  				key.context.cfg.UseGCMIVFromHSM && !key.context.cfg.GCMIVFromHSMControl.SupplyIvForHSMGCMDecrypt) {
    79  				params = pkcs11.NewGCMParams(nil, additionalData, 16*8 /*bits*/)
    80  			} else {
    81  				params = pkcs11.NewGCMParams(nonce, additionalData, 16*8 /*bits*/)
    82  			}
    83  			return []*pkcs11.Mechanism{pkcs11.NewMechanism(key.Cipher.GCMMech, params)}, params, nil
    84  		},
    85  	}
    86  	return g, nil
    87  }
    88  
    89  // NewCBC returns a given cipher wrapped in CBC mode.
    90  //
    91  // Despite the cipher.AEAD return type, there is no support for additional data and no authentication.
    92  // This method exists to provide a convenient way to do bulk (possibly padded) CBC encryption.
    93  // Think carefully before passing the cipher.AEAD to any consumer that expects authentication.
    94  func (key *SecretKey) NewCBC(paddingMode PaddingMode) (cipher.AEAD, error) {
    95  
    96  	var pkcsMech uint
    97  
    98  	switch paddingMode {
    99  	case PaddingNone:
   100  		pkcsMech = key.Cipher.CBCMech
   101  	case PaddingPKCS:
   102  		pkcsMech = key.Cipher.CBCPKCSMech
   103  	default:
   104  		return nil, errors.New("unrecognized padding mode")
   105  	}
   106  
   107  	g := genericAead{
   108  		key:       key,
   109  		overhead:  0,
   110  		nonceSize: key.BlockSize(),
   111  		makeMech: func(nonce []byte, additionalData []byte, encrypt bool) ([]*pkcs11.Mechanism, *pkcs11.GCMParams, error) {
   112  			if len(additionalData) > 0 {
   113  				return nil, nil, errors.New("additional data not supported for CBC mode")
   114  			}
   115  
   116  			return []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcsMech, nonce)}, nil, nil
   117  		},
   118  	}
   119  
   120  	return g, nil
   121  }
   122  
   123  func (g genericAead) NonceSize() int {
   124  	return g.nonceSize
   125  }
   126  
   127  func (g genericAead) Overhead() int {
   128  	return g.overhead
   129  }
   130  
   131  func (g genericAead) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
   132  
   133  	var result []byte
   134  	if err := g.key.context.withSession(func(session *pkcs11Session) (err error) {
   135  		mech, params, err := g.makeMech(nonce, additionalData, true)
   136  
   137  		if err != nil {
   138  			return err
   139  		}
   140  		defer params.Free()
   141  
   142  		if err = session.ctx.EncryptInit(session.handle, mech, g.key.handle); err != nil {
   143  			err = fmt.Errorf("C_EncryptInit: %v", err)
   144  			return
   145  		}
   146  		if result, err = session.ctx.Encrypt(session.handle, plaintext); err != nil {
   147  			err = fmt.Errorf("C_Encrypt: %v", err)
   148  			return
   149  		}
   150  
   151  		if g.key.context.cfg.UseGCMIVFromHSM && g.key.context.cfg.GCMIVFromHSMControl.SupplyIvForHSMGCMEncrypt {
   152  			if len(nonce) != len(params.IV()) {
   153  				return errBadGCMNonceSize
   154  			}
   155  		}
   156  
   157  		return
   158  	}); err != nil {
   159  		panic(err)
   160  	} else {
   161  		dst = append(dst, result...)
   162  	}
   163  	return dst
   164  }
   165  
   166  func (g genericAead) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
   167  	var result []byte
   168  	if err := g.key.context.withSession(func(session *pkcs11Session) (err error) {
   169  		mech, params, err := g.makeMech(nonce, additionalData, false)
   170  		if err != nil {
   171  			return
   172  		}
   173  		defer params.Free()
   174  
   175  		if err = session.ctx.DecryptInit(session.handle, mech, g.key.handle); err != nil {
   176  			err = fmt.Errorf("C_DecryptInit: %v", err)
   177  			return
   178  		}
   179  		if result, err = session.ctx.Decrypt(session.handle, ciphertext); err != nil {
   180  			err = fmt.Errorf("C_Decrypt: %v", err)
   181  			return
   182  		}
   183  		return
   184  	}); err != nil {
   185  		return nil, err
   186  	}
   187  	dst = append(dst, result...)
   188  	return dst, nil
   189  }
   190  

View as plain text