1 // Copyright 2015 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.
5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
10 #include "base/logging.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/strings/string_util.h"
13 #include "crypto/aes_128_gcm_helpers_nss.h"
14 #include "crypto/scoped_nss_types.h"
18 bool GCMMessageCryptographer::EncryptDecryptRecordInternal(
20 const base::StringPiece
& input
,
21 const base::StringPiece
& key
,
22 const base::StringPiece
& nonce
,
23 std::string
* output
) const {
27 key_item
.type
= siBuffer
;
28 key_item
.data
= const_cast<unsigned char*>(
29 reinterpret_cast<const unsigned char*>(key
.data()));
30 key_item
.len
= key
.size();
32 const CK_ATTRIBUTE_TYPE cka_mode
= mode
== ENCRYPT
? CKA_ENCRYPT
35 // TODO(peter): For AES-GCM we should be using CKM_AES_GCM as the mechanism,
36 // but because of an NSS bug we need to use CKM_AES_ECB as a work-around until
37 // we require NSS 3.15+. https://bugzilla.mozilla.org/show_bug.cgi?id=853285
38 // This does not affect the call to PK11{Decrypt,Encrypt}Helper below.
39 const CK_MECHANISM_TYPE key_mechanism
= CKM_AES_ECB
;
41 crypto::ScopedPK11Slot
slot(PK11_GetInternalSlot());
42 crypto::ScopedPK11SymKey
aead_key(PK11_ImportSymKey(slot
.get(), key_mechanism
,
43 PK11_OriginUnwrap
, cka_mode
, &key_item
, nullptr));
45 CK_GCM_PARAMS gcm_params
;
46 gcm_params
.pIv
= const_cast<unsigned char*>(
47 reinterpret_cast<const unsigned char*>(nonce
.data()));
48 gcm_params
.ulIvLen
= nonce
.size();
50 gcm_params
.pAAD
= nullptr;
51 gcm_params
.ulAADLen
= 0;
53 gcm_params
.ulTagBits
= kAuthenticationTagBytes
* 8;
56 param
.type
= siBuffer
;
57 param
.data
= reinterpret_cast<unsigned char*>(&gcm_params
);
58 param
.len
= sizeof(gcm_params
);
60 base::CheckedNumeric
<size_t> maximum_output_length(input
.size());
62 maximum_output_length
+= kAuthenticationTagBytes
;
64 // WriteInto requires the buffer to finish with a NULL-byte.
65 maximum_output_length
+= 1;
67 unsigned int output_length
= 0;
68 unsigned char* raw_input
= const_cast<unsigned char*>(
69 reinterpret_cast<const unsigned char*>(input
.data()));
70 unsigned char* raw_output
= reinterpret_cast<unsigned char*>(
71 base::WriteInto(output
, maximum_output_length
.ValueOrDie()));
73 if (mode
== ENCRYPT
) {
74 if (crypto::PK11EncryptHelper(aead_key
.get(), CKM_AES_GCM
, ¶m
,
75 raw_output
, &output_length
, output
->size(),
76 raw_input
, input
.size())
81 if (crypto::PK11DecryptHelper(aead_key
.get(), CKM_AES_GCM
, ¶m
,
82 raw_output
, &output_length
, output
->size(),
83 raw_input
, input
.size())
89 base::CheckedNumeric
<size_t> expected_output_length(input
.size());
91 expected_output_length
+= kAuthenticationTagBytes
;
93 expected_output_length
-= kAuthenticationTagBytes
;
95 DCHECK_EQ(expected_output_length
.ValueOrDie(), output_length
);
97 output
->resize(output_length
);