Терминальный проект КиберПлат [open source]
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

498 lines
15KB

  1. /* @file Сервис, владеющий крипто-движком. */
  2. // Qt
  3. #include <Common/QtHeadersBegin.h>
  4. #include <QtCore/QString>
  5. #include <QtCore/QDateTime>
  6. #include <QtCore/QDir>
  7. #include <QtCore/QFile>
  8. #include <QtCore/QByteArray>
  9. #include <Common/QtHeadersEnd.h>
  10. // SDK
  11. #include <SDK/PaymentProcessor/Core/INetworkService.h>
  12. // Modules
  13. #include <Crypt/ICryptEngine.h>
  14. #include <System/IApplication.h>
  15. #include <Common/ILog.h>
  16. // Project
  17. #include "Services/ServiceNames.h"
  18. #include "Services/SettingsService.h"
  19. #include "Services/CryptService.h"
  20. namespace PP = SDK::PaymentProcessor;
  21. //---------------------------------------------------------------------------
  22. namespace CServiceCore
  23. {
  24. const char DefaultPublicKey[] = "pubkeys.key";
  25. const char DefaultSecretKey[] = "secret.key";
  26. }
  27. //---------------------------------------------------------------------------
  28. CryptService * CryptService::instance(IApplication * aApplication)
  29. {
  30. return static_cast<CryptService *>(aApplication->getCore()->getService(CServices::CryptService));
  31. }
  32. //---------------------------------------------------------------------------
  33. CryptService::CryptService(IApplication * aApplication)
  34. : mApplication(aApplication),
  35. mLog(aApplication->getLog())
  36. {
  37. }
  38. //---------------------------------------------------------------------------
  39. CryptService::~CryptService()
  40. {
  41. }
  42. //---------------------------------------------------------------------------
  43. bool CryptService::initialize()
  44. {
  45. ICryptEngine & crypt = CCryptEngine::instance();
  46. if (!crypt.initialize())
  47. {
  48. LOG(mLog, LogLevel::Error, "Failed to initialize CryptEngine.");
  49. return false;
  50. }
  51. // Подготавливаем к работе пары ключей.
  52. PP::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PP::TerminalSettings>();
  53. QList<QByteArray> passwords = crypt.getRootPassword();
  54. if (passwords.isEmpty())
  55. {
  56. LOG(mLog, LogLevel::Error, "Failed to generate root key password.");
  57. return false;
  58. }
  59. // Создаем ключ терминала.
  60. PP::SKeySettings terminalKey;
  61. terminalKey.serialNumber = 12345678;
  62. terminalKey.publicKeyPath = mApplication->getUserDataPath().append("/keys/rootp.key");
  63. terminalKey.secretKeyPath = mApplication->getUserDataPath().append("/keys/roots.key");
  64. bool result = false;
  65. // Перебираем все возможные пароли для ключей терминала.
  66. foreach (const QByteArray & password, passwords)
  67. {
  68. terminalKey.secretPassword = QString::fromLatin1(password.data(), password.size());
  69. QString error;
  70. result = crypt.loadKeyPair(-1, CCrypt::ETypeEngine::File, terminalKey.secretKeyPath, terminalKey.secretPassword,
  71. terminalKey.publicKeyPath, terminalKey.serialNumber, terminalKey.serialNumber, error);
  72. if (result)
  73. {
  74. break;
  75. }
  76. }
  77. if (!result || !QFile::exists(terminalKey.publicKeyPath) || !QFile::exists(terminalKey.secretKeyPath))
  78. {
  79. // Ключ не подошёл или отсутвует, надо создать.
  80. QString keyPath = mApplication->getUserDataPath() + "/keys";
  81. QDir keysDir;
  82. QString error;
  83. if (!keysDir.mkpath(keyPath))
  84. {
  85. LOG(mLog, LogLevel::Error, QString("Failed to create key path: %1.").arg(keyPath));
  86. return false;
  87. }
  88. QString backupExt = QDateTime::currentDateTime().toString(".yyyy-MM-dd_hh-mm-ss") + "_backup";
  89. QFile::rename(terminalKey.secretKeyPath, terminalKey.secretKeyPath + backupExt);
  90. QFile::rename(terminalKey.publicKeyPath, terminalKey.publicKeyPath + backupExt);
  91. if (!crypt.createKeyPair(keyPath, "root", "CyberPlat", terminalKey.secretPassword, terminalKey.serialNumber, error))
  92. {
  93. LOG(mLog, LogLevel::Error, QString("Failed to create terminal key pair. Error: %1.").arg(error));
  94. return false;
  95. }
  96. LOG(mLog, LogLevel::Normal, "Terminal key pair created.");
  97. // Пробуем загрузить созданный ключ
  98. if (!crypt.loadKeyPair(-1, CCrypt::ETypeEngine::File, terminalKey.secretKeyPath, terminalKey.secretPassword,
  99. terminalKey.publicKeyPath, terminalKey.serialNumber, terminalKey.serialNumber, error))
  100. {
  101. LOG(mLog, LogLevel::Error, QString("Failed to load terminal key pair. Error: %1.").arg(error));
  102. return false;
  103. }
  104. }
  105. terminalKey.isValid = true;
  106. mKeys.insert(-1, terminalKey);
  107. // Загружаем остальные ключи.
  108. foreach (PP::SKeySettings key, settings->getKeys().values())
  109. {
  110. loadKey(key);
  111. }
  112. // Проверяем, что первый ключ был корректно загружен.
  113. if (mKeys.value(0).isValid)
  114. {
  115. // Пишем в лог информацию ключе по умолчанию.
  116. LOG(mLog, LogLevel::Normal, QString("Default terminal key: SD %1, AP %2, OP %3.")
  117. .arg(mKeys.value(0).sd).arg(mKeys.value(0).ap).arg(mKeys.value(0).op));
  118. }
  119. else
  120. {
  121. LOG(mLog, LogLevel::Error, "Terminal default key is not valid.");
  122. }
  123. return true;
  124. }
  125. //------------------------------------------------------------------------------
  126. void CryptService::loadKey(SDK::PaymentProcessor::SKeySettings & aKey)
  127. {
  128. QString error;
  129. ICryptEngine & crypt = CCryptEngine::instance();
  130. aKey.isValid = false;
  131. // Преобразовываем пути к ключам.
  132. QString secretKeyPath;
  133. if (!QDir::isAbsolutePath(aKey.secretKeyPath))
  134. {
  135. secretKeyPath = QDir::cleanPath(mApplication->getUserDataPath() + "/" + aKey.secretKeyPath);
  136. }
  137. else
  138. {
  139. secretKeyPath = QDir::cleanPath(aKey.secretKeyPath);
  140. }
  141. QString publicKeyPath;
  142. if (!QDir::isAbsolutePath(aKey.publicKeyPath))
  143. {
  144. publicKeyPath = QDir::cleanPath(mApplication->getUserDataPath() + "/" + aKey.publicKeyPath);
  145. }
  146. else
  147. {
  148. publicKeyPath = QDir::cleanPath(aKey.publicKeyPath);
  149. }
  150. // Пытаемся расшифровать кодовую фразу.
  151. QByteArray secretPassword = aKey.secretPassword.toLatin1();
  152. QByteArray decryptedSecretPassword;
  153. // Для Token не нужен шифрованный пароль
  154. if (aKey.engine == CCrypt::ETypeEngine::RuToken ||
  155. crypt.decrypt(-1, secretPassword, decryptedSecretPassword, error))
  156. {
  157. aKey.secretPassword = QString::fromLatin1(decryptedSecretPassword.data());
  158. if (!crypt.loadKeyPair(aKey.id, static_cast<CCrypt::ETypeEngine>(aKey.engine),
  159. secretKeyPath, aKey.secretPassword, publicKeyPath, aKey.serialNumber, aKey.bankSerialNumber, error))
  160. {
  161. LOG(mLog, LogLevel::Error, QString("Failed to load key pair %1 with encrypted password. Error: %2.").arg(aKey.id).arg(error));
  162. }
  163. else
  164. {
  165. aKey.isValid = true;
  166. }
  167. }
  168. else
  169. {
  170. // Пытаемся загрузить пару ключей без шифрования
  171. if (!crypt.loadKeyPair(aKey.id, static_cast<CCrypt::ETypeEngine>(aKey.engine),
  172. secretKeyPath, QString::fromLatin1(secretPassword.data()), publicKeyPath, aKey.serialNumber, aKey.bankSerialNumber, error))
  173. {
  174. LOG(mLog, LogLevel::Error, QString("Failed to load key pair %1 with unencrypted password. Error: %2.").arg(aKey.id).arg(error));
  175. }
  176. else
  177. {
  178. aKey.isValid = true;
  179. LOG(mLog, LogLevel::Warning, QString("Key pair %1 has unencrypted secret password.").arg(aKey.id));
  180. }
  181. }
  182. mKeys.insert(aKey.id, aKey);
  183. }
  184. //------------------------------------------------------------------------------
  185. void CryptService::finishInitialize()
  186. {
  187. }
  188. //---------------------------------------------------------------------------
  189. bool CryptService::canShutdown()
  190. {
  191. return true;
  192. }
  193. //---------------------------------------------------------------------------
  194. bool CryptService::shutdown()
  195. {
  196. CCryptEngine::instance().releaseKeyPairs();
  197. CCryptEngine::instance().shutdown();
  198. return true;
  199. }
  200. //---------------------------------------------------------------------------
  201. QString CryptService::getName() const
  202. {
  203. return CServices::CryptService;
  204. }
  205. //---------------------------------------------------------------------------
  206. const QSet<QString> & CryptService::getRequiredServices() const
  207. {
  208. static QSet<QString> requiredServices = QSet<QString>()
  209. << CServices::SettingsService;
  210. return requiredServices;
  211. }
  212. //---------------------------------------------------------------------------
  213. QVariantMap CryptService::getParameters() const
  214. {
  215. return QVariantMap();
  216. }
  217. //---------------------------------------------------------------------------
  218. void CryptService::resetParameters(const QSet<QString> &)
  219. {
  220. }
  221. //---------------------------------------------------------------------------
  222. PP::SKeySettings CryptService::getKey(int aId) const
  223. {
  224. if (mKeys.contains(aId))
  225. {
  226. return mKeys[aId];
  227. }
  228. else
  229. {
  230. return PP::SKeySettings();
  231. }
  232. }
  233. //---------------------------------------------------------------------------
  234. bool CryptService::addKey(const PP::SKeySettings & aKey)
  235. {
  236. if (aKey.isValid)
  237. {
  238. // добавляем в список ключей
  239. mKeys.insert(aKey.id, aKey);
  240. PP::SKeySettings key = aKey;
  241. // Шифруем кодовую фразу
  242. QByteArray encryptedPhrase;
  243. QString error;
  244. if (aKey.engine == CCrypt::ETypeEngine::File)
  245. {
  246. if (!CCryptEngine::instance().encrypt(-1, aKey.secretPassword.toLatin1(), encryptedPhrase, CCrypt::ETypeKey::Public, error))
  247. {
  248. LOG(mLog, LogLevel::Error, QString("Failed to encrypt password phrase for key pair %1, serial = %2. Error: %3.")
  249. .arg(key.id).arg(key.bankSerialNumber).arg(error));
  250. return false;
  251. }
  252. key.secretPassword = QString::fromLatin1(encryptedPhrase);
  253. }
  254. // Добавляем запись в дерево настроек.
  255. PP::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PP::TerminalSettings>();
  256. // Сериализуем настройки.
  257. settings->setKey(key);
  258. return true;
  259. }
  260. return false;
  261. }
  262. //---------------------------------------------------------------------------
  263. int CryptService::generateKey(int aKeyId, const QString & aLogin, const QString & aPassword, const QString & aURL, QString & aSD, QString & aAP, QString & aOP)
  264. {
  265. PP::INetworkService * networkService = mApplication->getCore()->getNetworkService();
  266. if (!networkService->isConnected() && !networkService->openConnection(true))
  267. {
  268. LOG(mLog, LogLevel::Error, QString("Key %1 generation failed. Unable to establish connection.").arg(aKeyId));
  269. return EKeysUtilsError::NetworkError;
  270. }
  271. SKeyPair keyPair;
  272. EKeysUtilsError::Enum result;
  273. if ((result = createKeyPair(getCryptEngine(), aKeyId, networkService->getNetworkTaskManager(), aURL, aLogin, aPassword, keyPair)) != EKeysUtilsError::Ok)
  274. {
  275. LOG(mLog, LogLevel::Error, QString("Failed to create key pair %1. Error is %2").arg(aKeyId).arg(EKeysUtilsError::errorToString(result)));
  276. return result;
  277. }
  278. mKeyPair = keyPair;
  279. if ((result = registerKeyPair(getCryptEngine(), aKeyId, networkService->getNetworkTaskManager(), aURL, aLogin, aPassword, mKeyPair)) != EKeysUtilsError::Ok)
  280. {
  281. LOG(mLog, LogLevel::Error, QString("Failed to register key pair %1. Error is %2").arg(aKeyId).arg(EKeysUtilsError::errorToString(result)));
  282. return result;
  283. }
  284. LOG(mLog, LogLevel::Normal, QString("Key pair %1 with SD %2, AP %3, OP %4 is generated and registered successfully.")
  285. .arg(aKeyId).arg(QString(keyPair.sd)).arg(QString(keyPair.ap)).arg(QString(keyPair.op)));
  286. aAP = keyPair.ap;
  287. aSD = keyPair.sd;
  288. aOP = keyPair.op;
  289. return EKeysUtilsError::Ok;
  290. }
  291. //---------------------------------------------------------------------------
  292. bool CryptService::replaceKeys(int aKeyIdSrc, int aKeyIdDst)
  293. {
  294. bool result = false;
  295. if (mKeys.contains(aKeyIdSrc))
  296. {
  297. PP::SKeySettings keySrc = getKey(aKeyIdSrc);
  298. if (keySrc.isValid)
  299. {
  300. getCryptEngine()->releaseKeyPair(aKeyIdSrc);
  301. getCryptEngine()->releaseKeyPair(aKeyIdDst);
  302. PP::SKeySettings dstKey = keySrc;
  303. dstKey.id = aKeyIdDst;
  304. mKeys.remove(aKeyIdSrc);
  305. mKeys[aKeyIdDst] = dstKey;
  306. // загружаем новый ключ в память
  307. loadKey(dstKey);
  308. PP::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PP::TerminalSettings>();
  309. // чистим список ключей
  310. settings->cleanKeys();
  311. // сохраняем заново список действующих ключей
  312. foreach (auto key, mKeys)
  313. {
  314. if (key.id >= 0)
  315. {
  316. addKey(key);
  317. }
  318. }
  319. result = true;
  320. }
  321. }
  322. return result;
  323. }
  324. //---------------------------------------------------------------------------
  325. bool CryptService::saveKey()
  326. {
  327. LOG(mApplication->getLog(), LogLevel::Normal, QString("Saving key pair %1.").arg(mKeyPair.id));
  328. // Формируем и сохраяняем ключ.
  329. ICryptEngine * crypt = &CCryptEngine::instance();
  330. PP::SKeySettings key;
  331. key.id = mKeyPair.id;
  332. key.ap = mKeyPair.ap;
  333. key.op = mKeyPair.op;
  334. key.sd = mKeyPair.sd;
  335. key.engine = mKeyPair.engine;
  336. QByteArray serverPublicKey = mKeyPair.serverPublicKey;
  337. QString shortKeyPath = QString("keys/") + key.ap;
  338. QString fullKeyPath = mApplication->getUserDataPath() + "/" + shortKeyPath;
  339. if (QDir(fullKeyPath).exists())
  340. {
  341. // если такая папка с ключами существует, то создаем новую папку
  342. QDateTime currentDateTime = QDateTime::currentDateTime();
  343. shortKeyPath += currentDateTime.toString(".yyyyMMdd_hhmmss");
  344. fullKeyPath += currentDateTime.toString(".yyyyMMdd_hhmmss");
  345. }
  346. QString shortPublicKeyPath = shortKeyPath + "/" + CServiceCore::DefaultPublicKey;
  347. QString shortSecretKeyPath = shortKeyPath + "/" + CServiceCore::DefaultSecretKey;
  348. QString fullPublicKeyPath = fullKeyPath + "/" + CServiceCore::DefaultPublicKey;
  349. QString fullSecretKeyPath = fullKeyPath + "/" + CServiceCore::DefaultSecretKey;
  350. QDir keyDir;
  351. if (!keyDir.mkpath(fullKeyPath))
  352. {
  353. LOG(mApplication->getLog(), LogLevel::Error, QString("Failed to create directory: %1.").arg(fullKeyPath));
  354. return false;
  355. }
  356. // Сначала дампим свой открытый ключ
  357. if (!crypt->exportPublicKeyToFile(key.id, fullPublicKeyPath, key.serialNumber))
  358. {
  359. LOG(mApplication->getLog(), LogLevel::Error, "Failed to export public key.");
  360. return false;
  361. }
  362. // Потом открытый серверный
  363. if (!crypt->replacePublicKey(key.id, serverPublicKey))
  364. {
  365. LOG(mApplication->getLog(), LogLevel::Error, "Failed to replace public key.");
  366. return false;
  367. }
  368. if (!crypt->exportPublicKeyToFile(key.id, fullPublicKeyPath, key.bankSerialNumber))
  369. {
  370. LOG(mApplication->getLog(), LogLevel::Error, "Failed to export server public key.");
  371. return false;
  372. }
  373. key.publicKeyPath = shortPublicKeyPath;
  374. if (key.engine == CCrypt::ETypeEngine::File)
  375. {
  376. key.secretPassword = QString::fromLatin1(crypt->generatePassword());
  377. key.secretKeyPath = shortSecretKeyPath;
  378. if (!crypt->exportSecretKeyToFile(key.id, fullSecretKeyPath, key.secretPassword.toLatin1()))
  379. {
  380. LOG(mApplication->getLog(), LogLevel::Error, "Failed to export private key.");
  381. return false;
  382. }
  383. }
  384. // Обновляем конфигурационный файл с ключами.
  385. key.isValid = true;
  386. return addKey(key);
  387. }
  388. //---------------------------------------------------------------------------
  389. ICryptEngine * CryptService::getCryptEngine()
  390. {
  391. return &CCryptEngine::instance();
  392. }
  393. //---------------------------------------------------------------------------