Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crypto/hmac.h"
      6 
      7 #include <nss.h>
      8 #include <pk11pub.h>
      9 #include <stddef.h>
     10 
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "crypto/nss_util.h"
     14 #include "crypto/scoped_nss_types.h"
     15 
     16 namespace crypto {
     17 
     18 struct HMACPlatformData {
     19   CK_MECHANISM_TYPE mechanism_;
     20   ScopedPK11Slot slot_;
     21   ScopedPK11SymKey sym_key_;
     22 };
     23 
     24 HMAC::HMAC(HashAlgorithm hash_alg)
     25     : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
     26   // Only SHA-1 and SHA-256 hash algorithms are supported.
     27   switch (hash_alg_) {
     28     case SHA1:
     29       plat_->mechanism_ = CKM_SHA_1_HMAC;
     30       break;
     31     case SHA256:
     32       plat_->mechanism_ = CKM_SHA256_HMAC;
     33       break;
     34     default:
     35       NOTREACHED() << "Unsupported hash algorithm";
     36       break;
     37   }
     38 }
     39 
     40 HMAC::~HMAC() {
     41 }
     42 
     43 bool HMAC::Init(const unsigned char *key, size_t key_length) {
     44   EnsureNSSInit();
     45 
     46   if (plat_->slot_.get()) {
     47     // Init must not be called more than twice on the same HMAC object.
     48     NOTREACHED();
     49     return false;
     50   }
     51 
     52   plat_->slot_.reset(PK11_GetInternalSlot());
     53   if (!plat_->slot_.get()) {
     54     NOTREACHED();
     55     return false;
     56   }
     57 
     58   SECItem key_item;
     59   key_item.type = siBuffer;
     60   key_item.data = const_cast<unsigned char*>(key);  // NSS API isn't const.
     61   key_item.len = key_length;
     62 
     63   plat_->sym_key_.reset(PK11_ImportSymKey(plat_->slot_.get(),
     64                                           plat_->mechanism_,
     65                                           PK11_OriginUnwrap,
     66                                           CKA_SIGN,
     67                                           &key_item,
     68                                           NULL));
     69   if (!plat_->sym_key_.get()) {
     70     NOTREACHED();
     71     return false;
     72   }
     73 
     74   return true;
     75 }
     76 
     77 bool HMAC::Sign(const base::StringPiece& data,
     78                 unsigned char* digest,
     79                 size_t digest_length) const {
     80   if (!plat_->sym_key_.get()) {
     81     // Init has not been called before Sign.
     82     NOTREACHED();
     83     return false;
     84   }
     85 
     86   SECItem param = { siBuffer, NULL, 0 };
     87   ScopedPK11Context context(PK11_CreateContextBySymKey(plat_->mechanism_,
     88                                                        CKA_SIGN,
     89                                                        plat_->sym_key_.get(),
     90                                                        &param));
     91   if (!context.get()) {
     92     NOTREACHED();
     93     return false;
     94   }
     95 
     96   if (PK11_DigestBegin(context.get()) != SECSuccess) {
     97     NOTREACHED();
     98     return false;
     99   }
    100 
    101   if (PK11_DigestOp(context.get(),
    102                     reinterpret_cast<const unsigned char*>(data.data()),
    103                     data.length()) != SECSuccess) {
    104     NOTREACHED();
    105     return false;
    106   }
    107 
    108   unsigned int len = 0;
    109   if (PK11_DigestFinal(context.get(),
    110                        digest, &len, digest_length) != SECSuccess) {
    111     NOTREACHED();
    112     return false;
    113   }
    114 
    115   return true;
    116 }
    117 
    118 }  // namespace crypto
    119