blob: f4c38007356d65483ace0fad7d8f6af3fde4bb7c [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chaps/object_store_impl.h"
#include <map>
#include <string>
#include <base/logging.h>
#include <chromeos/utility.h>
#include <openssl/evp.h>
#include "chaps/chaps_utility.h"
#include "pkcs11/cryptoki.h"
using std::map;
using std::string;
namespace chaps {
const int ObjectStoreImpl::kAESBlockSizeBytes = 16;
const int ObjectStoreImpl::kAESKeySizeBytes = 32;
ObjectStoreImpl::ObjectStoreImpl() : cipher_() {
EVP_CIPHER_CTX_init(&cipher_context_);
}
ObjectStoreImpl::~ObjectStoreImpl() {
// TODO(dkrahn): Use SecureBlob. See crosbug.com/27681.
chromeos::SecureMemset(const_cast<char*>(key_.data()), 0, key_.length());
EVP_CIPHER_CTX_cleanup(&cipher_context_);
}
bool ObjectStoreImpl::GetInternalBlob(int blob_id, string* blob) {
return false;
}
bool ObjectStoreImpl::SetInternalBlob(int blob_id, const string& blob) {
return false;
}
bool ObjectStoreImpl::SetEncryptionKey(const string& key) {
if (key.length() != static_cast<size_t>(kAESKeySizeBytes)) {
LOG(ERROR) << "Unexpected key size: " << key.length();
return false;
}
key_ = key;
return true;
}
bool ObjectStoreImpl::InsertObjectBlob(bool is_private,
CK_OBJECT_CLASS object_class,
const string& key_id,
const string& blob,
int* handle) {
if (key_.empty())
return false;
return false;
}
bool ObjectStoreImpl::DeleteObjectBlob(int handle) {
if (key_.empty())
return false;
return false;
}
bool ObjectStoreImpl::UpdateObjectBlob(int handle, const string& blob) {
if (key_.empty())
return false;
return false;
}
bool ObjectStoreImpl::LoadAllObjectBlobs(map<int, string>* blobs) {
if (key_.empty())
return false;
return false;
}
bool ObjectStoreImpl::RunCipher(bool is_encrypt,
const string& input,
string* output) {
if (key_.empty()) {
LOG(ERROR) << "Store encryption key has not been initialized.";
return false;
}
int input_length = input.length();
string iv;
if (is_encrypt) {
// Generate a new random IV.
iv.resize(kAESBlockSizeBytes);
RAND_bytes(ConvertStringToByteBuffer(iv.data()), kAESBlockSizeBytes);
} else {
// Recover the IV from the input.
if (input_length < kAESBlockSizeBytes) {
LOG(ERROR) << "Decrypt: Invalid input.";
return false;
}
iv = input.substr(input_length - kAESBlockSizeBytes);
input_length -= kAESBlockSizeBytes;
}
if (!EVP_CipherInit_ex(&cipher_context_,
EVP_aes_256_cbc(),
NULL,
ConvertStringToByteBuffer(key_.data()),
ConvertStringToByteBuffer(iv.data()),
is_encrypt)) {
LOG(ERROR) << "EVP_CipherInit_ex failed: " << GetOpenSSLError();
return false;
}
EVP_CIPHER_CTX_set_padding(&cipher_context_,
1); // Enables PKCS padding.
// Set the buffer size to be large enough to hold all output. For encryption,
// this will allow space for padding and, for decryption, this will comply
// with openssl documentation (even though the final output will be no larger
// than input_length).
output->resize(input_length + kAESBlockSizeBytes);
int output_length = 0;
unsigned char* output_bytes = ConvertStringToByteBuffer(output->data());
unsigned char* input_bytes = ConvertStringToByteBuffer(input.data());
if (!EVP_CipherUpdate(&cipher_context_,
output_bytes,
&output_length, // Will be set to actual output length.
input_bytes,
input_length)) {
LOG(ERROR) << "EVP_CipherUpdate failed: " << GetOpenSSLError();
return false;
}
// The final block is yet to be computed. This check ensures we have at least
// kAESBlockSizeBytes bytes left in the output buffer.
CHECK(output_length <= input_length);
int output_length2 = 0;
if (!EVP_CipherFinal_ex(&cipher_context_,
output_bytes + output_length,
&output_length2)) {
LOG(ERROR) << "EVP_CipherFinal_ex failed: " << GetOpenSSLError();
return false;
}
// Adjust the output size to the number of bytes actually written.
output->resize(output_length + output_length2);
if (is_encrypt) {
// Append the IV so it will be available during decryption.
*output += iv;
}
return true;
}
bool ObjectStoreImpl::Encrypt(const string& plain_text,
string* cipher_text) {
return RunCipher(true, plain_text, cipher_text);
}
bool ObjectStoreImpl::Decrypt(const string& cipher_text,
string* plain_text) {
return RunCipher(false, cipher_text, plain_text);
}
} // namespace chaps