blob: ce705c54fe609d554bf4d7d23fb55de479ae60e2 [file] [log] [blame]
deanm@google.com6f19a382008-09-16 23:32:44 +09001// 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
deanm@google.com6f19a382008-09-16 23:32:44 +090014namespace {
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
deanm@google.com82be1f72008-09-17 18:42:51 +090038namespace base {
39
deanm@google.com6f19a382008-09-16 23:32:44 +090040struct HMACPlatformData {
41 ScopedNSSSlot slot_;
42 ScopedNSSSymKey sym_key_;
43};
44
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090045HMAC::HMAC(HashAlgorithm hash_alg)
deanm@google.com6f19a382008-09-16 23:32:44 +090046 : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090047 // Only SHA-1 digest is supported now.
deanm@google.com6f19a382008-09-16 23:32:44 +090048 DCHECK(hash_alg_ == SHA1);
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090049}
deanm@google.com6f19a382008-09-16 23:32:44 +090050
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090051bool HMAC::Init(const unsigned char *key, int key_length) {
deanm@google.com6f19a382008-09-16 23:32:44 +090052 base::EnsureNSSInit();
53
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090054 if (hash_alg_ != SHA1) {
55 NOTREACHED();
56 return false;
57 }
58
wtc@chromium.orgea749d22009-07-23 03:34:14 +090059 if (plat_->slot_.get()) {
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090060 // Init must not be called more than twice on the same HMAC object.
61 NOTREACHED();
62 return false;
63 }
64
deanm@google.com6f19a382008-09-16 23:32:44 +090065 plat_->slot_.reset(PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL));
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090066 if (!plat_->slot_.get()) {
67 NOTREACHED();
68 return false;
69 }
deanm@google.com6f19a382008-09-16 23:32:44 +090070
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));
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090082 if (!plat_->sym_key_.get()) {
83 NOTREACHED();
84 return false;
85 }
86
87 return true;
deanm@google.com6f19a382008-09-16 23:32:44 +090088}
89
90HMAC::~HMAC() {
deanm@google.com6f19a382008-09-16 23:32:44 +090091}
92
93bool HMAC::Sign(const std::string& data,
94 unsigned char* digest,
95 int digest_length) {
wtc@chromium.orgc56e5ca2009-05-06 08:55:59 +090096 if (!plat_->sym_key_.get()) {
97 // Init has not been called before Sign.
98 NOTREACHED();
99 return false;
100 }
101
deanm@google.com6f19a382008-09-16 23:32:44 +0900102 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