• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HMAC(HashAlgorithm hash_alg)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 
~HMAC()40 HMAC::~HMAC() {
41 }
42 
Init(const unsigned char * key,size_t key_length)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 
Sign(const base::StringPiece & data,unsigned char * digest,size_t digest_length) const77 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