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.
5 #include "crypto/encryptor.h"
9 #include "base/string_util.h"
10 #include "crypto/symmetric_key.h"
16 // On success, returns the block size (in bytes) for the algorithm that |key|
17 // is for. On failure, returns 0.
18 DWORD
GetCipherBlockSize(HCRYPTKEY key
) {
19 DWORD block_size_in_bits
= 0;
20 DWORD param_size
= sizeof(block_size_in_bits
);
21 BOOL ok
= CryptGetKeyParam(key
, KP_BLOCKLEN
,
22 reinterpret_cast<BYTE
*>(&block_size_in_bits
),
27 return block_size_in_bits
/ 8;
32 Encryptor::Encryptor()
38 Encryptor::~Encryptor() {
41 bool Encryptor::Init(SymmetricKey
* key
,
43 const base::StringPiece
& iv
) {
45 DCHECK_EQ(CBC
, mode
) << "Unsupported mode of operation";
47 // In CryptoAPI, the IV, padding mode, and feedback register (for a chaining
48 // mode) are properties of a key, so we have to create a copy of the key for
49 // the Encryptor. See the Remarks section of the CryptEncrypt MSDN page.
50 BOOL ok
= CryptDuplicateKey(key
->key(), NULL
, 0, capi_key_
.receive());
54 // CRYPT_MODE_CBC is the default for Microsoft Base Cryptographic Provider,
55 // but we set it anyway to be safe.
56 DWORD cipher_mode
= CRYPT_MODE_CBC
;
57 ok
= CryptSetKeyParam(capi_key_
.get(), KP_MODE
,
58 reinterpret_cast<BYTE
*>(&cipher_mode
), 0);
62 block_size_
= GetCipherBlockSize(capi_key_
.get());
66 if (iv
.size() != block_size_
)
69 ok
= CryptSetKeyParam(capi_key_
.get(), KP_IV
,
70 reinterpret_cast<const BYTE
*>(iv
.data()), 0);
74 DWORD padding_method
= PKCS5_PADDING
;
75 ok
= CryptSetKeyParam(capi_key_
.get(), KP_PADDING
,
76 reinterpret_cast<BYTE
*>(&padding_method
), 0);
83 bool Encryptor::Encrypt(const base::StringPiece
& plaintext
,
84 std::string
* ciphertext
) {
85 DWORD data_len
= plaintext
.size();
86 DWORD total_len
= data_len
+ block_size_
;
87 CHECK_GT(total_len
, data_len
);
89 // CryptoAPI encrypts/decrypts in place.
90 char* ciphertext_data
= WriteInto(ciphertext
, total_len
+ 1);
91 memcpy(ciphertext_data
, plaintext
.data(), data_len
);
93 BOOL ok
= CryptEncrypt(capi_key_
.get(), NULL
, TRUE
, 0,
94 reinterpret_cast<BYTE
*>(ciphertext_data
), &data_len
,
101 ciphertext
->resize(data_len
);
105 bool Encryptor::Decrypt(const base::StringPiece
& ciphertext
,
106 std::string
* plaintext
) {
107 DWORD data_len
= ciphertext
.size();
108 if (data_len
== 0 || (data_len
+ 1) < data_len
)
111 // CryptoAPI encrypts/decrypts in place.
112 char* plaintext_data
= WriteInto(plaintext
, data_len
+ 1);
113 memcpy(plaintext_data
, ciphertext
.data(), data_len
);
115 BOOL ok
= CryptDecrypt(capi_key_
.get(), NULL
, TRUE
, 0,
116 reinterpret_cast<BYTE
*>(plaintext_data
), &data_len
);
122 plaintext
->resize(data_len
);
126 } // namespace crypto