2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Zofia Abramowska (z.abramowska@samsung.com)
20 * @brief Implementation of encrypted db access layer
23 #include <db-crypto.h>
24 #include <dpl/db/sql_connection.h>
25 #include <dpl/log/log.h>
26 #include <ckm/ckm-error.h>
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
32 const char *main_table = "CKM_TABLE";
33 const char *key_table = "KEY_TABLE";
35 // CKM_TABLE (alias TEXT, label TEXT, restricted INT, exportable INT, dataType INT,
36 // algorithmType INT, encryptionScheme INT, iv BLOB, dataSize INT, data BLOB)
38 const char *db_create_main_cmd =
39 "CREATE TABLE CKM_TABLE("
40 " alias TEXT NOT NULL,"
41 " label TEXT NOT NULL,"
42 " restricted INTEGER NOT NULL,"
43 " exportable INTEGER NOT NULL,"
44 " dataType INTEGER NOT NULL,"
45 " algorithmType INTEGER NOT NULL,"
46 " encryptionScheme INTEGER NOT NULL,"
48 " dataSize INTEGER NOT NULL,"
49 " data BLOB NOT NULL,"
50 " PRIMARY KEY(alias, label),"
51 " UNIQUE(alias, restricted)"
55 const char *insert_main_cmd =
56 "INSERT INTO CKM_TABLE("
58 " alias, label, restricted, exportable,"
60 " dataType, algorithmType, encryptionScheme,"
62 " iv, dataSize, data) "
64 " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
66 const char *select_alias_cmd =
68 "SELECT * FROM CKM_TABLE WHERE alias=? AND dataType=? AND restricted=1 AND label=? "
71 " SELECT * FROM CKM_TABLE WHERE alias=? AND dataType=? AND restricted=0;";
73 const char *select_check_alias_cmd =
75 "SELECT dataType FROM CKM_TABLE WHERE alias=? AND label=? AND restricted=1; ";
77 const char *select_check_global_alias_cmd =
79 "SELECT label FROM CKM_TABLE WHERE alias=? AND restricted=0;";
81 const char *select_key_alias_cmd =
83 "SELECT * FROM CKM_TABLE WHERE alias=?"
85 " AND dataType BETWEEN ? AND ? "
87 " AND (restricted=0 OR label=?);";
89 const char *select_key_type_cmd =
90 "SELECT alias FROM CKM_TABLE WHERE "
96 " (restricted=0 OR label=?)";
98 const char *select_type_cmd =
100 "SELECT alias FROM CKM_TABLE WHERE dataType=? AND restricted=0 "
103 "SELECT alias FROM CKM_TABLE WHERE dataType=? AND restricted=1 AND label=?;";
105 const char *delete_alias_cmd =
107 "DELETE FROM CKM_TABLE WHERE alias=? AND label=?;";
109 // KEY_TABLE (label TEXT, key BLOB)
111 const char *db_create_key_cmd =
112 "CREATE TABLE KEY_TABLE("
113 " label TEXT PRIMARY KEY,"
117 const char *insert_key_cmd =
118 "INSERT INTO KEY_TABLE(label, key) VALUES (?, ?);";
119 const char *select_key_cmd =
120 "SELECT key FROM KEY_TABLE WHERE label=?;";
121 const char *delete_key_cmd =
122 "DELETE FROM KEY_TABLE WHERE label=?";
127 DBCrypto::DBCrypto(const std::string& path,
128 const RawBuffer &rawPass) {
130 m_inUserTransaction = false;
132 m_connection = new SqlConnection(path, SqlConnection::Flag::Option::CRW);
133 m_connection->SetKey(rawPass);
135 } Catch(SqlConnection::Exception::ConnectionBroken) {
136 LogError("Couldn't connect to database: " << path);
137 ReThrow(DBCrypto::Exception::InternalError);
138 } Catch(SqlConnection::Exception::InvalidArguments) {
139 LogError("Couldn't set the key for database");
140 ReThrow(DBCrypto::Exception::InternalError);
141 } Catch(SqlConnection::Exception::SyntaxError) {
142 LogError("Couldn't initiate the database");
143 ReThrow(DBCrypto::Exception::InternalError);
144 } Catch(SqlConnection::Exception::InternalError) {
145 LogError("Couldn't create the database");
146 ReThrow(DBCrypto::Exception::InternalError);
150 DBCrypto::DBCrypto(DBCrypto &&other) :
151 m_connection(other.m_connection),
152 m_inUserTransaction(other.m_inUserTransaction){
153 other.m_connection = NULL;
154 other.m_inUserTransaction = false;
157 DBCrypto::~DBCrypto() {
161 DBCrypto& DBCrypto::operator=(DBCrypto&& other) {
166 m_connection = other.m_connection;
167 other.m_connection = NULL;
169 m_inUserTransaction = other.m_inUserTransaction;
170 other.m_inUserTransaction = false;
175 void DBCrypto::createTable(
176 const char* create_cmd,
177 const char *table_name)
180 m_connection->ExecCommand(create_cmd);
181 } Catch(SqlConnection::Exception::SyntaxError) {
182 LogError("Couldn't create table : " << table_name << "!");
187 void DBCrypto::initDatabase() {
188 Transaction transaction(this);
189 if(!m_connection->CheckTableExist(main_table)) {
190 createTable(db_create_main_cmd, main_table);
192 if(!m_connection->CheckTableExist(key_table)) {
193 createTable(db_create_key_cmd, key_table);
195 transaction.commit();
198 bool DBCrypto::checkGlobalAliasExist(const std::string& alias) {
199 SqlConnection::DataCommandUniquePtr checkCmd =
200 m_connection->PrepareDataCommand(select_check_global_alias_cmd);
201 checkCmd->BindString(1, alias.c_str());
202 if(checkCmd->Step()) {
203 LogDebug("Global alias '" << alias << "' exists already for label "
204 << checkCmd->GetColumnString(0));
210 bool DBCrypto::checkAliasExist(
211 const std::string& alias,
212 const std::string& label) {
213 SqlConnection::DataCommandUniquePtr checkCmd =
214 m_connection->PrepareDataCommand(select_check_alias_cmd);
215 checkCmd->BindString(1, alias.c_str());
216 checkCmd->BindString(2, label.c_str());
217 if(checkCmd->Step()) {
218 LogDebug("Private alias '" << alias << "' exists already for type "
219 << checkCmd->GetColumnInteger(0));
225 void DBCrypto::saveDBRow(const DBRow &row){
228 //Sqlite does not support partial index in our version,
229 //so we do it by hand
230 Transaction transaction(this);
231 if((row.restricted == 1 && checkAliasExist(row.alias, row.smackLabel)) ||
232 (row.restricted == 0 && checkGlobalAliasExist(row.alias))) {
233 ThrowMsg(DBCrypto::Exception::AliasExists,
234 "Alias exists for alias: " << row.alias
235 << ", label: " << row.smackLabel);
238 SqlConnection::DataCommandUniquePtr insertCommand =
239 m_connection->PrepareDataCommand(insert_main_cmd);
240 insertCommand->BindString(1, row.alias.c_str());
241 insertCommand->BindString(2, row.smackLabel.c_str());
242 insertCommand->BindInteger(3, row.restricted);
243 insertCommand->BindInteger(4, row.exportable);
244 insertCommand->BindInteger(5, static_cast<int>(row.dataType));
245 insertCommand->BindInteger(6, static_cast<int>(row.algorithmType));
246 insertCommand->BindInteger(7, row.encryptionScheme);
247 insertCommand->BindBlob(8, row.iv);
248 insertCommand->BindInteger(9, row.dataSize);
249 insertCommand->BindBlob(10, row.data);
251 insertCommand->Step();
252 transaction.commit();
255 } Catch(SqlConnection::Exception::SyntaxError) {
256 LogError("Couldn't prepare insert statement");
257 } Catch(SqlConnection::Exception::InternalError) {
258 LogError("Couldn't execute insert statement");
260 ThrowMsg(DBCrypto::Exception::InternalError,
261 "Couldn't save DBRow");
264 DBRow DBCrypto::getRow(const SqlConnection::DataCommandUniquePtr &selectCommand) {
266 row.alias = selectCommand->GetColumnString(0);
267 row.smackLabel = selectCommand->GetColumnString(1);
268 row.restricted = selectCommand->GetColumnInteger(2);
269 row.exportable = selectCommand->GetColumnInteger(3);
270 row.dataType = static_cast<DBDataType>(selectCommand->GetColumnInteger(4));
271 row.algorithmType = static_cast<DBCMAlgType>(selectCommand->GetColumnInteger(5));
272 row.encryptionScheme = selectCommand->GetColumnInteger(6);
273 row.iv = selectCommand->GetColumnBlob(7);
274 row.dataSize = selectCommand->GetColumnInteger(8);
275 row.data = selectCommand->GetColumnBlob(9);
279 DBCrypto::DBRowOptional DBCrypto::getDBRow(
281 const std::string &label,
285 Transaction transaction(this);
286 SqlConnection::DataCommandUniquePtr selectCommand =
287 m_connection->PrepareDataCommand(select_alias_cmd);
288 selectCommand->BindString(1, alias.c_str());
289 selectCommand->BindInteger(2, static_cast<int>(type));
290 selectCommand->BindString(3, label.c_str());
291 selectCommand->BindString(4, alias.c_str());
292 selectCommand->BindInteger(5, static_cast<int>(type));
294 if(selectCommand->Step()) {
295 transaction.commit();
296 return DBRowOptional(getRow(selectCommand));
298 return DBRowOptional();
300 } Catch (SqlConnection::Exception::InvalidColumn) {
301 LogError("Select statement invalid column error");
302 } Catch (SqlConnection::Exception::SyntaxError) {
303 LogError("Couldn't prepare select statement");
304 } Catch (SqlConnection::Exception::InternalError) {
305 LogError("Couldn't execute select statement");
307 ThrowMsg(DBCrypto::Exception::InternalError,
308 "Couldn't get row for type " << static_cast<int>(type) <<
309 " alias " << alias << " and label " << label);
312 DBCrypto::DBRowOptional DBCrypto::getKeyDBRow(
314 const std::string &label)
317 Transaction transaction(this);
318 SqlConnection::DataCommandUniquePtr selectCommand =
319 m_connection->PrepareDataCommand(select_key_alias_cmd);
320 selectCommand->BindString(1, alias.c_str());
321 selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_FIRST));
322 selectCommand->BindInteger(3, static_cast<int>(DBDataType::DB_KEY_LAST));
323 selectCommand->BindString(4, label.c_str());
325 if(selectCommand->Step()) {
326 transaction.commit();
327 return DBRowOptional(getRow(selectCommand));
329 return DBRowOptional();
331 } Catch (SqlConnection::Exception::InvalidColumn) {
332 LogError("Select statement invalid column error");
333 } Catch (SqlConnection::Exception::SyntaxError) {
334 LogError("Couldn't prepare select statement");
335 } Catch (SqlConnection::Exception::InternalError) {
336 LogError("Couldn't execute select statement");
338 ThrowMsg(DBCrypto::Exception::InternalError,
339 "Couldn't get Key for alias " << alias
340 << " and label " << label);
343 void DBCrypto::getSingleType(
345 const std::string& label,
346 AliasVector& aliases)
349 SqlConnection::DataCommandUniquePtr selectCommand =
350 m_connection->PrepareDataCommand(select_type_cmd);
351 selectCommand->BindInteger(1, static_cast<int>(type));
352 selectCommand->BindInteger(2, static_cast<int>(type));
353 selectCommand->BindString(3, label.c_str());
355 while(selectCommand->Step()) {
357 alias = selectCommand->GetColumnString(0);
358 aliases.push_back(alias);
361 } Catch (SqlConnection::Exception::InvalidColumn) {
362 LogError("Select statement invalid column error");
363 } Catch (SqlConnection::Exception::SyntaxError) {
364 LogError("Couldn't prepare select statement");
365 } Catch (SqlConnection::Exception::InternalError) {
366 LogError("Couldn't execute select statement");
368 ThrowMsg(DBCrypto::Exception::InternalError,
369 "Couldn't get type " << static_cast<int>(type)
370 << " for label " << label);
373 void DBCrypto::getAliases(
375 const std::string& label,
376 AliasVector& aliases)
378 getSingleType(type, label, aliases);
382 void DBCrypto::getKeyAliases(
383 const std::string &label,
384 AliasVector &aliases)
387 Transaction transaction(this);
388 SqlConnection::DataCommandUniquePtr selectCommand =
389 m_connection->PrepareDataCommand(select_key_type_cmd);
390 selectCommand->BindInteger(1, static_cast<int>(DBDataType::DB_KEY_FIRST));
391 selectCommand->BindInteger(2, static_cast<int>(DBDataType::DB_KEY_LAST));
392 selectCommand->BindString(3, label.c_str());
394 while(selectCommand->Step()) {
396 alias = selectCommand->GetColumnString(0);
397 aliases.push_back(alias);
399 transaction.commit();
401 } Catch (SqlConnection::Exception::InvalidColumn) {
402 LogError("Select statement invalid column error");
403 } Catch (SqlConnection::Exception::SyntaxError) {
404 LogError("Couldn't prepare select statement");
405 } Catch (SqlConnection::Exception::InternalError) {
406 LogError("Couldn't execute select statement");
408 ThrowMsg(DBCrypto::Exception::InternalError,
409 "Couldn't get key aliases for label " << label);
412 void DBCrypto::deleteDBRow(
414 const std::string &label)
417 Transaction transaction(this);
418 SqlConnection::DataCommandUniquePtr deleteCommand =
419 m_connection->PrepareDataCommand(delete_alias_cmd);
420 deleteCommand->BindString(1, alias.c_str());
421 deleteCommand->BindString(2, label.c_str());
422 deleteCommand->Step();
423 transaction.commit();
425 } Catch (SqlConnection::Exception::SyntaxError) {
426 LogError("Couldn't prepare delete statement");
427 } Catch (SqlConnection::Exception::InternalError) {
428 LogError("Couldn't execute delete statement");
430 ThrowMsg(DBCrypto::Exception::InternalError,
431 "Couldn't delete DBRow for alias " << alias
432 << " and label " << label);
435 void DBCrypto::saveKey(
436 const std::string& label,
437 const RawBuffer &key)
440 Transaction transaction(this);
441 SqlConnection::DataCommandUniquePtr insertCommand =
442 m_connection->PrepareDataCommand(insert_key_cmd);
443 insertCommand->BindString(1, label.c_str());
444 insertCommand->BindBlob(2, key);
445 insertCommand->Step();
446 transaction.commit();
448 } Catch (SqlConnection::Exception::SyntaxError) {
449 LogError("Couldn't prepare insert key statement");
450 } Catch (SqlConnection::Exception::InternalError) {
451 LogError("Couldn't execute insert statement");
453 ThrowMsg(DBCrypto::Exception::InternalError,
454 "Couldn't save key for label " << label);
457 DBCrypto::RawBufferOptional DBCrypto::getKey(
458 const std::string& label)
461 Transaction transaction(this);
462 SqlConnection::DataCommandUniquePtr selectCommand =
463 m_connection->PrepareDataCommand(select_key_cmd);
464 selectCommand->BindString(1, label.c_str());
466 if (selectCommand->Step()) {
467 transaction.commit();
468 return RawBufferOptional(
469 selectCommand->GetColumnBlob(0));
471 transaction.commit();
472 return RawBufferOptional();
475 } Catch (SqlConnection::Exception::InvalidColumn) {
476 LogError("Select statement invalid column error");
477 } Catch (SqlConnection::Exception::SyntaxError) {
478 LogError("Couldn't prepare insert key statement");
479 } Catch (SqlConnection::Exception::InternalError) {
480 LogError("Couldn't execute insert statement");
482 ThrowMsg(DBCrypto::Exception::InternalError,
483 "Couldn't get key for label " << label);
486 void DBCrypto::deleteKey(const std::string& label) {
488 Transaction transaction(this);
489 SqlConnection::DataCommandUniquePtr deleteCommand =
490 m_connection->PrepareDataCommand(delete_key_cmd);
491 deleteCommand->BindString(1, label.c_str());
492 deleteCommand->Step();
493 transaction.commit();
495 } Catch (SqlConnection::Exception::SyntaxError) {
496 LogError("Couldn't prepare insert key statement");
497 } Catch (SqlConnection::Exception::InternalError) {
498 LogError("Couldn't execute insert statement");
500 ThrowMsg(DBCrypto::Exception::InternalError,
501 "Couldn't delete key for label " << label);
506 #pragma GCC diagnostic pop