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 ¶m)); 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