blob: ce705c54fe609d554bf4d7d23fb55de479ae60e2 [file] [log] [blame]
[email protected]bc1e07c72008-09-16 14:32:441// Copyright (c) 2008 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 "base/hmac.h"
6
7#include <nss.h>
8#include <pk11pub.h>
9
10#include "base/logging.h"
11#include "base/nss_init.h"
12#include "base/scoped_ptr.h"
13
[email protected]bc1e07c72008-09-16 14:32:4414namespace {
15
16template <typename Type, void (*Destroyer)(Type*)>
17struct NSSDestroyer {
18 void operator()(Type* ptr) const {
19 if (ptr)
20 Destroyer(ptr);
21 }
22};
23
24void DestroyContext(PK11Context* context) {
25 PK11_DestroyContext(context, PR_TRUE);
26}
27
28// Define some convenient scopers around NSS pointers.
29typedef scoped_ptr_malloc<
30 PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot> > ScopedNSSSlot;
31typedef scoped_ptr_malloc<
32 PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey> > ScopedNSSSymKey;
33typedef scoped_ptr_malloc<
34 PK11Context, NSSDestroyer<PK11Context, DestroyContext> > ScopedNSSContext;
35
36} // namespace
37
[email protected]c1444fe2008-09-17 09:42:5138namespace base {
39
[email protected]bc1e07c72008-09-16 14:32:4440struct HMACPlatformData {
41 ScopedNSSSlot slot_;
42 ScopedNSSSymKey sym_key_;
43};
44
[email protected]d91f8432009-05-05 23:55:5945HMAC::HMAC(HashAlgorithm hash_alg)
[email protected]bc1e07c72008-09-16 14:32:4446 : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
[email protected]d91f8432009-05-05 23:55:5947 // Only SHA-1 digest is supported now.
[email protected]bc1e07c72008-09-16 14:32:4448 DCHECK(hash_alg_ == SHA1);
[email protected]d91f8432009-05-05 23:55:5949}
[email protected]bc1e07c72008-09-16 14:32:4450
[email protected]d91f8432009-05-05 23:55:5951bool HMAC::Init(const unsigned char *key, int key_length) {
[email protected]bc1e07c72008-09-16 14:32:4452 base::EnsureNSSInit();
53
[email protected]d91f8432009-05-05 23:55:5954 if (hash_alg_ != SHA1) {
55 NOTREACHED();
56 return false;
57 }
58
[email protected]2f89e6a22009-07-22 18:34:1459 if (plat_->slot_.get()) {
[email protected]d91f8432009-05-05 23:55:5960 // Init must not be called more than twice on the same HMAC object.
61 NOTREACHED();
62 return false;
63 }
64
[email protected]bc1e07c72008-09-16 14:32:4465 plat_->slot_.reset(PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL));
[email protected]d91f8432009-05-05 23:55:5966 if (!plat_->slot_.get()) {
67 NOTREACHED();
68 return false;
69 }
[email protected]bc1e07c72008-09-16 14:32:4470
71 SECItem key_item;
72 key_item.type = siBuffer;
73 key_item.data = const_cast<unsigned char*>(key); // NSS API isn't const.
74 key_item.len = key_length;
75
76 plat_->sym_key_.reset(PK11_ImportSymKey(plat_->slot_.get(),
77 CKM_SHA_1_HMAC,
78 PK11_OriginUnwrap,
79 CKA_SIGN,
80 &key_item,
81 NULL));
[email protected]d91f8432009-05-05 23:55:5982 if (!plat_->sym_key_.get()) {
83 NOTREACHED();
84 return false;
85 }
86
87 return true;
[email protected]bc1e07c72008-09-16 14:32:4488}
89
90HMAC::~HMAC() {
[email protected]bc1e07c72008-09-16 14:32:4491}
92
93bool HMAC::Sign(const std::string& data,
94 unsigned char* digest,
95 int digest_length) {
[email protected]d91f8432009-05-05 23:55:5996 if (!plat_->sym_key_.get()) {
97 // Init has not been called before Sign.
98 NOTREACHED();
99 return false;
100 }
101
[email protected]bc1e07c72008-09-16 14:32:44102 SECItem param = { siBuffer, NULL, 0 };
103 ScopedNSSContext context(PK11_CreateContextBySymKey(CKM_SHA_1_HMAC,
104 CKA_SIGN,
105 plat_->sym_key_.get(),
106 &param));
107 if (!context.get()) {
108 NOTREACHED();
109 return false;
110 }
111
112 if (PK11_DigestBegin(context.get()) != SECSuccess) {
113 NOTREACHED();
114 return false;
115 }
116
117 if (PK11_DigestOp(context.get(),
118 reinterpret_cast<const unsigned char*>(data.data()),
119 data.length()) != SECSuccess) {
120 NOTREACHED();
121 return false;
122 }
123
124 unsigned int len = 0;
125 if (PK11_DigestFinal(context.get(),
126 digest, &len, digest_length) != SECSuccess) {
127 NOTREACHED();
128 return false;
129 }
130
131 return true;
132}
133
134} // namespace base