...

Source file src/github.com/ThalesIgnite/crypto11/hmac.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  	"errors"
    26  	"hash"
    27  
    28  	"github.com/miekg/pkcs11"
    29  )
    30  
    31  const (
    32  	// NFCK_VENDOR_NCIPHER distinguishes nShield vendor-specific mechanisms.
    33  	NFCK_VENDOR_NCIPHER = 0xde436972
    34  
    35  	// CKM_NCIPHER is the base for nShield vendor-specific mechanisms.
    36  	CKM_NCIPHER = (pkcs11.CKM_VENDOR_DEFINED | NFCK_VENDOR_NCIPHER)
    37  
    38  	// CKM_NC_MD5_HMAC_KEY_GEN is the nShield-specific HMACMD5 key-generation mechanism
    39  	CKM_NC_MD5_HMAC_KEY_GEN = (CKM_NCIPHER + 0x6)
    40  
    41  	// CKM_NC_SHA_1_HMAC_KEY_GEN is the nShield-specific HMACSHA1 key-generation mechanism
    42  	CKM_NC_SHA_1_HMAC_KEY_GEN = (CKM_NCIPHER + 0x3)
    43  
    44  	// CKM_NC_SHA224_HMAC_KEY_GEN is the nShield-specific HMACSHA224 key-generation mechanism
    45  	CKM_NC_SHA224_HMAC_KEY_GEN = (CKM_NCIPHER + 0x24)
    46  
    47  	// CKM_NC_SHA256_HMAC_KEY_GEN is the nShield-specific HMACSHA256 key-generation mechanism
    48  	CKM_NC_SHA256_HMAC_KEY_GEN = (CKM_NCIPHER + 0x25)
    49  
    50  	// CKM_NC_SHA384_HMAC_KEY_GEN is the nShield-specific HMACSHA384 key-generation mechanism
    51  	CKM_NC_SHA384_HMAC_KEY_GEN = (CKM_NCIPHER + 0x26)
    52  
    53  	// CKM_NC_SHA512_HMAC_KEY_GEN is the nShield-specific HMACSHA512 key-generation mechanism
    54  	CKM_NC_SHA512_HMAC_KEY_GEN = (CKM_NCIPHER + 0x27)
    55  )
    56  
    57  type hmacImplementation struct {
    58  	// PKCS#11 session to use
    59  	session *pkcs11Session
    60  
    61  	// Signing key
    62  	key *SecretKey
    63  
    64  	// Hash size
    65  	size int
    66  
    67  	// Block size
    68  	blockSize int
    69  
    70  	// PKCS#11 mechanism information
    71  	mechDescription []*pkcs11.Mechanism
    72  
    73  	// Cleanup function
    74  	cleanup func()
    75  
    76  	// Count of updates
    77  	updates uint64
    78  
    79  	// Result, or nil if we don't have the answer yet
    80  	result []byte
    81  }
    82  
    83  type hmacInfo struct {
    84  	size      int
    85  	blockSize int
    86  	general   bool
    87  }
    88  
    89  var hmacInfos = map[int]*hmacInfo{
    90  	pkcs11.CKM_MD5_HMAC:                {20, 64, false},
    91  	pkcs11.CKM_MD5_HMAC_GENERAL:        {20, 64, true},
    92  	pkcs11.CKM_SHA_1_HMAC:              {20, 64, false},
    93  	pkcs11.CKM_SHA_1_HMAC_GENERAL:      {20, 64, true},
    94  	pkcs11.CKM_SHA224_HMAC:             {28, 64, false},
    95  	pkcs11.CKM_SHA224_HMAC_GENERAL:     {28, 64, true},
    96  	pkcs11.CKM_SHA256_HMAC:             {32, 64, false},
    97  	pkcs11.CKM_SHA256_HMAC_GENERAL:     {32, 64, true},
    98  	pkcs11.CKM_SHA384_HMAC:             {48, 64, false},
    99  	pkcs11.CKM_SHA384_HMAC_GENERAL:     {48, 64, true},
   100  	pkcs11.CKM_SHA512_HMAC:             {64, 128, false},
   101  	pkcs11.CKM_SHA512_HMAC_GENERAL:     {64, 128, true},
   102  	pkcs11.CKM_SHA512_224_HMAC:         {28, 128, false},
   103  	pkcs11.CKM_SHA512_224_HMAC_GENERAL: {28, 128, true},
   104  	pkcs11.CKM_SHA512_256_HMAC:         {32, 128, false},
   105  	pkcs11.CKM_SHA512_256_HMAC_GENERAL: {32, 128, true},
   106  	pkcs11.CKM_RIPEMD160_HMAC:          {20, 64, false},
   107  	pkcs11.CKM_RIPEMD160_HMAC_GENERAL:  {20, 64, true},
   108  }
   109  
   110  // errHmacClosed is called if an HMAC is updated after it has finished.
   111  var errHmacClosed = errors.New("already called Sum()")
   112  
   113  // NewHMAC returns a new HMAC hash using the given PKCS#11 mechanism
   114  // and key.
   115  // length specifies the output size, for _GENERAL mechanisms.
   116  //
   117  // If the mechanism is not in the built-in list of known mechanisms then the
   118  // Size() function will return whatever length was, even if it is wrong.
   119  // BlockSize() will always return 0 in this case.
   120  //
   121  // The Reset() method is not implemented.
   122  // After Sum() is called no new data may be added.
   123  func (key *SecretKey) NewHMAC(mech int, length int) (hash.Hash, error) {
   124  	hi := hmacImplementation{
   125  		key: key,
   126  	}
   127  	var params []byte
   128  	if info, ok := hmacInfos[mech]; ok {
   129  		hi.blockSize = info.blockSize
   130  		if info.general {
   131  			hi.size = length
   132  			params = ulongToBytes(uint(length))
   133  		} else {
   134  			hi.size = info.size
   135  		}
   136  	} else {
   137  		hi.size = length
   138  	}
   139  	hi.mechDescription = []*pkcs11.Mechanism{pkcs11.NewMechanism(uint(mech), params)}
   140  	if err := hi.initialize(); err != nil {
   141  		return nil, err
   142  	}
   143  	return &hi, nil
   144  }
   145  
   146  func (hi *hmacImplementation) initialize() (err error) {
   147  	session, err := hi.key.context.getSession()
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	hi.session = session
   153  	hi.cleanup = func() {
   154  		hi.key.context.pool.Put(session)
   155  		hi.session = nil
   156  	}
   157  	if err = hi.session.ctx.SignInit(hi.session.handle, hi.mechDescription, hi.key.handle); err != nil {
   158  		hi.cleanup()
   159  		return
   160  	}
   161  	hi.updates = 0
   162  	hi.result = nil
   163  	return
   164  }
   165  
   166  func (hi *hmacImplementation) Write(p []byte) (n int, err error) {
   167  	if hi.result != nil {
   168  		if len(p) > 0 {
   169  			err = errHmacClosed
   170  		}
   171  		return
   172  	}
   173  	if err = hi.session.ctx.SignUpdate(hi.session.handle, p); err != nil {
   174  		return
   175  	}
   176  	hi.updates++
   177  	n = len(p)
   178  	return
   179  }
   180  
   181  func (hi *hmacImplementation) Sum(b []byte) []byte {
   182  	if hi.result == nil {
   183  		var err error
   184  		if hi.updates == 0 {
   185  			// http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html#_Toc322855304
   186  			// We must ensure that C_SignUpdate is called _at least once_.
   187  			if err = hi.session.ctx.SignUpdate(hi.session.handle, []byte{}); err != nil {
   188  				panic(err)
   189  			}
   190  		}
   191  		hi.result, err = hi.session.ctx.SignFinal(hi.session.handle)
   192  		hi.cleanup()
   193  		if err != nil {
   194  			panic(err)
   195  		}
   196  	}
   197  	return append(b, hi.result...)
   198  }
   199  
   200  func (hi *hmacImplementation) Reset() {
   201  	hi.Sum(nil) // Clean up
   202  
   203  	// Assign the error to "_" to indicate we are knowingly ignoring this. It may have been
   204  	// sensible to panic at this stage, but we cannot add a panic without breaking backwards
   205  	// compatibility.
   206  	_ = hi.initialize()
   207  }
   208  
   209  func (hi *hmacImplementation) Size() int {
   210  	return hi.size
   211  }
   212  
   213  func (hi *hmacImplementation) BlockSize() int {
   214  	return hi.blockSize
   215  }
   216  

View as plain text