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