cryptolib.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jexcept.hpp"
  14. #include "digisign.hpp"
  15. #include "ske.hpp"
  16. #include "dadfs.hpp"
  17. #include "dautils.hpp"
  18. #include <openssl/rand.h>
  19. #include <unordered_map>
  20. #include "cryptolib.hpp"
  21. using namespace std;
  22. #define CRYPTOLIB_VERSION "CRYPTOLIB 1.0.00"
  23. using namespace cryptohelper;
  24. static const char * EclDefinition = nullptr;//Definitions specified in lib_cryptolib.ecllib
  25. CRYPTOLIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  26. {
  27. // Warning: This function may be called without the plugin being loaded fully.
  28. // It should not make any library calls or assume that dependent modules
  29. // have been loaded or that it has been initialized.
  30. //
  31. // Specifically: "The system does not call DllMain for process and thread
  32. // initialization and termination. Also, the system does not load
  33. // additional executable modules that are referenced by the specified module."
  34. if (pb->size != sizeof(ECLPluginDefinitionBlock))
  35. return false;
  36. pb->magicVersion = PLUGIN_VERSION;
  37. pb->version = CRYPTOLIB_VERSION;
  38. pb->moduleName = "lib_cryptolib";
  39. pb->ECL = EclDefinition;
  40. pb->flags = PLUGIN_IMPLICIT_MODULE;
  41. pb->description = "CryptoLib cryptography services library";
  42. return true;
  43. }
  44. namespace nsCryptolib {
  45. IPluginContext * parentCtx = nullptr;
  46. }
  47. using namespace nsCryptolib;
  48. CRYPTOLIB_API void setPluginContext(IPluginContext * _ctx) { parentCtx = _ctx; }
  49. //-------------------------------------------------------------------------------------------------------------------------------------------
  50. // C++ to ECL helpers
  51. //-------------------------------------------------------------------------------------------------------------------------------------------
  52. size32_t addToECLSetOfString(void * set, const char * str)
  53. {
  54. size32_t len = strlen(str);
  55. if (len)
  56. {
  57. memcpy(set, &len, sizeof(len));//copy 4 byte length. String Set memory buffer should already be allocated within the context
  58. memcpy((char *)set + sizeof(len), str, strlen(str));//followed by string
  59. }
  60. return len + sizeof(len);//return length copied to memory buffer
  61. }
  62. void stringArrayToECLSetOfString(const StringArray & arr, void * * set, size32_t * len)
  63. {
  64. //STRING is a variable length string stored as a 4 byte length, followed by the string. A set of strings has
  65. //the strings in this format repeated, and the total size returned in the __lenResult parameter. The __result value should be allocated
  66. //on the heap.
  67. size32_t currLen = 0;
  68. for (aindex_t idx = 0; idx < arr.length(); idx++)
  69. currLen += strlen(arr.item(idx)) + sizeof(size32_t);
  70. void * pSet = CTXMALLOC(parentCtx, currLen);
  71. assertex(set);
  72. *len = currLen;
  73. *set = pSet;
  74. currLen = 0;
  75. for (aindex_t idx = 0; idx < arr.length(); idx++)
  76. currLen += addToECLSetOfString((char*)pSet + currLen, arr.item(idx));
  77. }
  78. //-------------------------------------------------------------------------------------------------------------------------------------------
  79. // CIPHER SYMMETRIC SUPPORT
  80. //-------------------------------------------------------------------------------------------------------------------------------------------
  81. //NB: It should be noted that we count on the cryptohelper library to call OpenSSL_add_all_algorithms() at init time
  82. void my_clAlgorithmsCallback(const OBJ_NAME * _obj, void * _pRes)
  83. {
  84. ((StringArray*)_pRes)->append((const char*)_obj->name);//add this digest to string array
  85. }
  86. //NB: CRYPTOLIB call signatures can be gleaned from the generated workunit CPP file
  87. //Symmetric block/stream digest algorithms
  88. CRYPTOLIB_API void CRYPTOLIB_CALL clInstalledSymmetricCipherAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  89. {
  90. __isAllResult = false;
  91. StringArray algorithms;
  92. OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, my_clAlgorithmsCallback, (void*)&algorithms);
  93. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  94. }
  95. CRYPTOLIB_API void CRYPTOLIB_CALL clSupportedSymmetricCipherAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  96. {
  97. __isAllResult = false;
  98. StringArray algorithms;
  99. algorithms.appendList("aes-256-cbc,aes-192-cbc,aes-128-cbc", ",");//make sure this list matches loadEVP_Cipher()
  100. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  101. }
  102. //-------------------------------------------------------------------------------------------------------------------------------------------
  103. //Helpers to build the DATA buffer returned from clSymmetricEncrypt, and sent to clSymmetricDecrypt
  104. //Buffer is structured as:
  105. // (size32_t)lenIV, IV excluding NULL, (size32_t)LenPlainText excluding NULL, (size32_t)LenCipher, Cipher
  106. static void symmDeserialize(const void * pBuffer, StringBuffer & sbIV, StringBuffer & sbCipher, size32_t * lenPlainText)
  107. {
  108. size32_t len;
  109. const char * finger = (const char *)pBuffer;
  110. memcpy(&len, finger, sizeof(size32_t));//extract IV
  111. finger += sizeof(size32_t);
  112. sbIV.append(len, finger);
  113. finger += len;
  114. memcpy(lenPlainText, finger, sizeof(size32_t));//extract length of plain text
  115. finger += sizeof(size32_t);
  116. memcpy(&len, finger, sizeof(size32_t));//extract cipher
  117. finger += sizeof(size32_t);
  118. sbCipher.append(len, finger);
  119. }
  120. static void symmSerialize(void * & result, size32_t & lenResult, const char * pIV, size32_t lenIV, size32_t lenPlainText, size32_t lenCipherBuff, const void * pCipherBuff)
  121. {
  122. //Allocate return DATA buffer
  123. lenResult = sizeof(size32_t) + lenIV + sizeof(size32_t) + sizeof(size32_t) + lenCipherBuff;
  124. result = CTXMALLOC(parentCtx, lenResult);
  125. //build result DATA buffer in the form:
  126. char * pRes = (char *)result;
  127. memcpy(pRes, &lenIV, sizeof(size32_t));//copy size of IV
  128. pRes += sizeof(size32_t);
  129. memcpy(pRes, pIV, lenIV);//copy the IV
  130. pRes += lenIV;
  131. memcpy(pRes, &lenPlainText, sizeof(size32_t));
  132. pRes += sizeof(size32_t);
  133. memcpy(pRes, &lenCipherBuff, sizeof(size32_t));
  134. pRes += sizeof(size32_t);
  135. memcpy(pRes, pCipherBuff, lenCipherBuff);
  136. }
  137. //-------------------------------------------------------------------------------------------------------------------------------------------
  138. void verifySymmetricAlgorithm(const char * algorithm, size32_t len)
  139. {
  140. if (strieq(algorithm, "aes-128-cbc"))
  141. {
  142. if (len != 16)
  143. throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 16", len, algorithm);
  144. }
  145. else if (strieq(algorithm, "aes-192-cbc"))
  146. {
  147. if (len != 24)
  148. throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 24", len, algorithm);
  149. }
  150. else if (strieq(algorithm, "aes-256-cbc"))
  151. {
  152. if (len != 32)
  153. throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 32", len, algorithm);
  154. }
  155. else
  156. throw makeStringExceptionV(-1, "Unsupported symmetric algorithm (%s) specified", algorithm);
  157. }
  158. CRYPTOLIB_API void CRYPTOLIB_CALL clSymmetricEncrypt(size32_t & __lenResult, void * & __result,
  159. const char * algorithm,
  160. const char * key,
  161. size32_t lenInputdata,const void * inputdata)
  162. {
  163. verifySymmetricAlgorithm(algorithm, strlen(key) );
  164. //Create a unique Initialization Vector
  165. unsigned char iv[EVP_MAX_IV_LENGTH];
  166. RAND_bytes(iv, EVP_MAX_IV_LENGTH);
  167. //temporary buffer for result
  168. MemoryBuffer out;
  169. aesEncrypt(out, lenInputdata, inputdata, strlen(key), key, (const char *)iv);
  170. //build result DATA buffer in the form:
  171. // (size32_t)EVP_MAX_IV_LENGTH, IV, (size32_t)LenPlainText excluding NULL, (size32_t)LenCipher, Cipher
  172. symmSerialize(__result, __lenResult, (const char *)iv, sizeof(iv), lenInputdata, out.length(), (const void *)out.bufferBase());
  173. }
  174. CRYPTOLIB_API void CRYPTOLIB_CALL clSymmetricDecrypt(size32_t & __lenResult,void * & __result,
  175. const char * algorithm,
  176. const char * key,
  177. size32_t lenEncrypteddata,const void * encrypteddata)
  178. {
  179. verifySymmetricAlgorithm(algorithm, strlen(key));
  180. //Decompose DATA buffer
  181. StringBuffer sbIV;
  182. StringBuffer sbCipher;
  183. size32_t lenPlainText;
  184. symmDeserialize(encrypteddata, sbIV, sbCipher, &lenPlainText);
  185. __result = (char *)CTXMALLOC(parentCtx, lenPlainText);
  186. __lenResult = lenPlainText;
  187. MemoryBuffer decrypted;
  188. size32_t len = aesDecrypt(decrypted, sbCipher.length(), sbCipher.str(), strlen(key), key, sbIV.str());
  189. memcpy(__result, decrypted.toByteArray(), __lenResult);
  190. }
  191. //-------------------------------------------------------------------------------------------------------------------------------------------
  192. // HASH SUPPORT
  193. //-------------------------------------------------------------------------------------------------------------------------------------------
  194. CRYPTOLIB_API void CRYPTOLIB_CALL clInstalledHashAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  195. {
  196. __isAllResult = false;
  197. StringArray algorithms;
  198. OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, my_clAlgorithmsCallback, (void*)&algorithms);
  199. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  200. }
  201. CRYPTOLIB_API void CRYPTOLIB_CALL clSupportedHashAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  202. {
  203. __isAllResult = false;
  204. StringArray algorithms;
  205. algorithms.appendList("SHA1,SHA224,SHA256,SHA384,SHA512", ",");//make sure these match algorithms in clHash()
  206. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  207. }
  208. void throwHashError(const char * str)
  209. {
  210. unsigned long err = ERR_get_error();
  211. char errStr[1024];
  212. ERR_error_string_n(err, errStr, sizeof(errStr));
  213. throw makeStringExceptionV(-1, "%s : ERROR %ld (0x%lX) : %s", str, err, err, errStr);
  214. }
  215. CRYPTOLIB_API void CRYPTOLIB_CALL clHash(size32_t & __lenResult, void * & __result,
  216. const char * algorithm,
  217. size32_t lenInputData, const void * inputData)
  218. {
  219. //Make sure each algorithm is included in clHashAlgorithms()
  220. if (strieq("SHA1", algorithm))
  221. {
  222. SHA_CTX context;
  223. if (!SHA1_Init(&context))
  224. throwHashError("OpenSSL ERROR calling SHA1_Init");
  225. if (!SHA1_Update(&context, (unsigned char*)inputData, lenInputData))
  226. throwHashError("OpenSSL ERROR calling SHA1_Update");
  227. __lenResult = SHA_DIGEST_LENGTH;//20 bytes
  228. __result = CTXMALLOC(parentCtx, __lenResult);
  229. if (!SHA1_Final((unsigned char *)__result, &context))
  230. {
  231. free(__result);
  232. throwHashError("OpenSSL ERROR calling SHA1_Final");
  233. }
  234. }
  235. else if (strieq("SHA224", algorithm))
  236. {
  237. SHA256_CTX context;//SHA224 uses the SHA256 context
  238. if (!SHA224_Init(&context))
  239. throwHashError("OpenSSL ERROR calling SHA224_Init");
  240. if (!SHA224_Update(&context, (unsigned char*)inputData, lenInputData))
  241. throwHashError("OpenSSL ERROR calling SHA224_Update");
  242. __lenResult = SHA224_DIGEST_LENGTH;//28 bytes
  243. __result = CTXMALLOC(parentCtx, __lenResult);
  244. if (!SHA224_Final((unsigned char *)__result, &context))
  245. {
  246. free(__result);
  247. throwHashError("OpenSSL ERROR calling SHA224_Final");
  248. }
  249. }
  250. else if (strieq("SHA256", algorithm))
  251. {
  252. SHA256_CTX context;
  253. if (!SHA256_Init(&context))
  254. throwHashError("OpenSSL ERROR calling SHA256_Init");
  255. if (!SHA256_Update(&context, (unsigned char*)inputData, lenInputData))
  256. throwHashError("OpenSSL ERROR calling SHA256_Update");
  257. __lenResult = SHA256_DIGEST_LENGTH;//32 bytes
  258. __result = CTXMALLOC(parentCtx, __lenResult);
  259. if (!SHA256_Final((unsigned char *)__result, &context))
  260. {
  261. free(__result);
  262. throwHashError("OpenSSL ERROR calling SHA256_Final");
  263. }
  264. }
  265. else if (strieq("SHA384", algorithm))
  266. {
  267. SHA512_CTX context;//SHA384 uses the SHA512 context
  268. if (!SHA384_Init(&context))
  269. throwHashError("OpenSSL ERROR calling SHA384_Init");
  270. if (!SHA384_Update(&context, (unsigned char*)inputData, lenInputData))
  271. throwHashError("OpenSSL ERROR calling SHA384_Update");
  272. __lenResult = SHA384_DIGEST_LENGTH;//48 bytes
  273. __result = CTXMALLOC(parentCtx, __lenResult);
  274. if (!SHA384_Final((unsigned char *)__result, &context))
  275. {
  276. free(__result);
  277. throwHashError("OpenSSL ERROR calling SHA384_Final");
  278. }
  279. }
  280. else if (strieq("SHA512", algorithm))
  281. {
  282. SHA512_CTX context;
  283. if (!SHA512_Init(&context))
  284. throwHashError("OpenSSL ERROR calling SHA512_Init");
  285. if (!SHA512_Update(&context, (unsigned char*)inputData, lenInputData))
  286. throwHashError("OpenSSL ERROR calling SHA512_Update");
  287. __lenResult = SHA512_DIGEST_LENGTH;//64 bytes
  288. __result = CTXMALLOC(parentCtx, __lenResult);
  289. if (!SHA512_Final((unsigned char *)__result, &context))
  290. {
  291. free(__result);
  292. throwHashError("OpenSSL ERROR calling SHA512_Final");
  293. }
  294. }
  295. else
  296. {
  297. throw makeStringExceptionV(-1, "Unsupported hash algorithm '%s' specified", algorithm);
  298. }
  299. }
  300. //-------------------------------------------------------------------------------------------------------------------------------------------
  301. // PUBLIC KEY SUPPORT
  302. //-------------------------------------------------------------------------------------------------------------------------------------------
  303. CRYPTOLIB_API void CRYPTOLIB_CALL clInstalledPublicKeyAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  304. {
  305. __isAllResult = false;
  306. StringArray algorithms;
  307. OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_PKEY_METH, my_clAlgorithmsCallback, (void*)&algorithms);
  308. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  309. }
  310. CRYPTOLIB_API void CRYPTOLIB_CALL clSupportedPublicKeyAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result)
  311. {
  312. __isAllResult = false;
  313. StringArray algorithms;
  314. algorithms.appendList("RSA", ",");
  315. stringArrayToECLSetOfString(algorithms, &__result, &__lenResult);
  316. }
  317. //signature helper function
  318. void doPKISign(size32_t & __lenResult, void * & __result,
  319. IDigitalSignatureManager * pDSM,
  320. size32_t lenInputdata, const void * inputdata)
  321. {
  322. StringBuffer sbSig;
  323. if (pDSM->digiSign(sbSig, lenInputdata, inputdata))
  324. {
  325. __result = CTXMALLOC(parentCtx, sbSig.length());
  326. __lenResult = sbSig.length();
  327. memcpy(__result, sbSig.str(), __lenResult);
  328. }
  329. else
  330. {
  331. throw makeStringException(-1, "Unable to create Digital Signature");
  332. }
  333. }
  334. void verifyPKIAlgorithm(const char * pkAlgorithm)
  335. {
  336. if (!strieq(pkAlgorithm, "RSA"))
  337. throw makeStringExceptionV(-1, "Unsupported PKI algorithm (%s) specified", pkAlgorithm);
  338. }
  339. //---------------------------------------------------------
  340. // Helper that reads the given logical file into a string buffer
  341. // Throws if user does not have read permission or if FNF
  342. //---------------------------------------------------------
  343. void loadLFS(const char * lfs, IUserDescriptor * user, StringBuffer &sb)
  344. {
  345. CDfsLogicalFileName lfn;
  346. lfn.set(lfs);
  347. try
  348. {
  349. Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(lfn, user, false, false, false, nullptr, defaultPrivilegedUser);//scope checks
  350. if (!df)
  351. {
  352. throw makeStringExceptionV(-1, "File %s Not Found", lfs);
  353. }
  354. if (df->numParts() == 0)
  355. {
  356. throw makeStringExceptionV(-1, "File %s is Empty", lfs);
  357. }
  358. IDistributedFilePart &part = df->queryPart(0);
  359. RemoteFilename rfn;
  360. Owned<IFile> file = createIFile(part.getFilename(rfn));
  361. if (!file->exists())
  362. {
  363. throw makeStringExceptionV(-1, "File %s Not Found", lfs);
  364. }
  365. Owned<IFileIO> io = file->open(IFOread);
  366. offset_t len = file->size();
  367. char * buff = sb.reserveTruncate(len);
  368. size32_t read = io->read(0, len, buff);
  369. assertex(read == len);
  370. //IFileIO dtor closes the file
  371. }
  372. catch(IException * e)
  373. {
  374. StringBuffer s;
  375. VStringBuffer sb("Error accessing Key file '%s' : %s", lfs, e->errorMessage(s).str());
  376. e->Release();
  377. throw makeStringException(-1, sb.str());
  378. }
  379. }
  380. //-----------------------------------------------------------------
  381. // Simple cache for instances of Digital Signature Managers
  382. //-----------------------------------------------------------------
  383. class CDSMCache
  384. {
  385. private:
  386. CriticalSection csDSMCache;//guards modifications to the cache map
  387. typedef std::unordered_map<string, Owned<IDigitalSignatureManager>> DSMCache;
  388. DSMCache dsmCache;
  389. public:
  390. IDigitalSignatureManager * getInstance(const char * algo, const char * pubKeyFS, const char * pubKeyBuff, const char * privKeyFS, const char * privKeyBuff, const char * passphrase, bool isLFN, IUserDescriptor * user)
  391. {
  392. VStringBuffer searchKey("%s_%s_%s_%s_%s_%s", algo, isEmptyString(pubKeyFS) ? "" : pubKeyFS, isEmptyString(pubKeyBuff) ? "" : pubKeyBuff,
  393. isEmptyString(privKeyFS) ? "" : privKeyFS, isEmptyString(privKeyBuff) ? "" : privKeyBuff, passphrase);
  394. CriticalBlock block(csDSMCache);
  395. DSMCache::iterator it = dsmCache.find(searchKey.str());
  396. IDigitalSignatureManager * ret = nullptr;
  397. if (it != dsmCache.end())//exists in cache
  398. {
  399. ret = (*it).second;
  400. }
  401. else
  402. {
  403. if (!isEmptyString(pubKeyFS) || !isEmptyString(privKeyFS))
  404. {
  405. bool isPublic = isEmptyString(privKeyFS);
  406. const char * fs = isPublic ? pubKeyFS : privKeyFS;;
  407. if (isLFN)
  408. {
  409. StringBuffer sb;
  410. loadLFS(fs, user, sb);//read key file into StringBuffer
  411. ret = createDigitalSignatureManagerInstanceFromKeys(isPublic ? sb.str() : nullptr, isPublic ? nullptr : sb.str(), passphrase);
  412. }
  413. else
  414. ret = createDigitalSignatureManagerInstanceFromFiles(pubKeyFS, privKeyFS, passphrase);
  415. }
  416. else
  417. ret = createDigitalSignatureManagerInstanceFromKeys(pubKeyBuff, privKeyBuff, passphrase);
  418. dsmCache.emplace(searchKey.str(), ret);
  419. }
  420. return LINK(ret);
  421. }
  422. };
  423. static CDSMCache g_DSMCache;
  424. //Sign given data using private key
  425. CRYPTOLIB_API void CRYPTOLIB_CALL clPKISign(size32_t & __lenResult,void * & __result,
  426. const char * pkalgorithm,
  427. const char * privatekeyfile,
  428. const char * passphrase,
  429. size32_t lenInputdata,const void * inputdata)
  430. {
  431. verifyPKIAlgorithm(pkalgorithm);//TODO extend cryptohelper to support more algorithms
  432. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, privatekeyfile, nullptr, passphrase, false, nullptr);
  433. if (pDSM)
  434. {
  435. doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
  436. }
  437. else
  438. {
  439. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  440. }
  441. }
  442. CRYPTOLIB_API void CRYPTOLIB_CALL clPKISignLFN(ICodeContext * ctx,
  443. size32_t & __lenResult,void * & __result,
  444. const char * pkalgorithm,
  445. const char * privatekeyLFN,
  446. const char * passphrase,
  447. size32_t lenInputdata,const void * inputdata)
  448. {
  449. verifyPKIAlgorithm(pkalgorithm);
  450. IUserDescriptor * udesc = ctx->queryUserDescriptor();
  451. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, privatekeyLFN, nullptr, passphrase, true, udesc);
  452. if (pDSM)
  453. {
  454. doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
  455. }
  456. else
  457. {
  458. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  459. }
  460. }
  461. CRYPTOLIB_API void CRYPTOLIB_CALL clPKISignBuff(size32_t & __lenResult, void * & __result,
  462. const char * pkalgorithm,
  463. const char * privatekeybuff,
  464. const char * passphrase,
  465. size32_t lenInputdata, const void * inputdata)
  466. {
  467. verifyPKIAlgorithm(pkalgorithm);
  468. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, nullptr, privatekeybuff, passphrase, false, nullptr);
  469. if (pDSM)
  470. {
  471. doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
  472. }
  473. else
  474. {
  475. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  476. }
  477. }
  478. CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignature(const char * pkalgorithm,
  479. const char * publickeyfile,
  480. const char * passphrase,
  481. size32_t lenSignature,const void * signature,
  482. size32_t lenSigneddata,const void * signeddata)
  483. {
  484. verifyPKIAlgorithm(pkalgorithm);
  485. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, publickeyfile, nullptr, nullptr, nullptr, passphrase, false, nullptr);
  486. if (pDSM)
  487. {
  488. StringBuffer sbSig(lenSignature, (const char *)signature);
  489. bool rc = pDSM->digiVerify(sbSig.str(), lenSigneddata, signeddata);
  490. return rc;
  491. }
  492. else
  493. {
  494. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  495. }
  496. }
  497. CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureLFN(ICodeContext * ctx,
  498. const char * pkalgorithm,
  499. const char * publickeyLFN,
  500. const char * passphrase,
  501. size32_t lenSignature,const void * signature,
  502. size32_t lenSigneddata,const void * signeddata)
  503. {
  504. verifyPKIAlgorithm(pkalgorithm);
  505. IUserDescriptor * udesc = ctx->queryUserDescriptor();
  506. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, publickeyLFN, nullptr, nullptr, nullptr, passphrase, true, udesc);
  507. if (pDSM)
  508. {
  509. StringBuffer sbSig(lenSignature, (const char *)signature);
  510. bool rc = pDSM->digiVerify(sbSig.str(), lenSigneddata, signeddata);
  511. return rc;
  512. }
  513. else
  514. {
  515. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  516. }
  517. }
  518. CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureBuff(const char * pkalgorithm,
  519. const char * publicKeyBuff,
  520. const char * passphrase,
  521. size32_t lenSignature, const void * signature,
  522. size32_t lenSigneddata, const void * signeddata)
  523. {
  524. verifyPKIAlgorithm(pkalgorithm);
  525. Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, publicKeyBuff, nullptr, nullptr, passphrase, false, nullptr);
  526. if (pDSM)
  527. {
  528. StringBuffer sbSig(lenSignature, (const char *)signature);
  529. bool rc = pDSM->digiVerify(sbSig.str(), lenSigneddata, signeddata);
  530. return rc;
  531. }
  532. else
  533. {
  534. throw makeStringException(-1, "Unable to create Digital Signature Manager");
  535. }
  536. }
  537. //-----------------------------------------------------------------
  538. // Simple cache for loaded keys
  539. //
  540. //-----------------------------------------------------------------
  541. #ifdef _USE_HASHMAP
  542. class CKeyCache : public CInterface
  543. {
  544. private:
  545. typedef std::unordered_map<string, Owned<CLoadedKey>> KeyCache;
  546. KeyCache keyCache;
  547. public:
  548. CLoadedKey * getInstance(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase)
  549. {
  550. if (isEmptyString(keyFS) && isEmptyString(keyBuff))
  551. throw makeStringExceptionV(-1, "Must specify a key filename or provide a key buffer");
  552. VStringBuffer searchKey("%s_%s_%s", isEmptyString(keyFS) ? "" : keyFS, isEmptyString(keyBuff) ? "" : keyBuff, isEmptyString(passphrase) ? "" : passphrase);
  553. KeyCache::iterator it = keyCache.find(searchKey.str());
  554. CLoadedKey * ret = nullptr;
  555. if (it != keyCache.end())//exists in cache?
  556. {
  557. ret = (*it).second;
  558. }
  559. else
  560. {
  561. if (!isEmptyString(keyFS))
  562. {
  563. //Create CLoadedKey from filespec
  564. if (isPublic)
  565. ret = loadPublicKeyFromFile(keyFS, passphrase);
  566. else
  567. ret = loadPrivateKeyFromFile(keyFS, passphrase);
  568. }
  569. else
  570. {
  571. //Create CLoadedKey from key contents
  572. if (isPublic)
  573. ret = loadPublicKeyFromMemory(keyBuff, passphrase);
  574. else
  575. ret = loadPrivateKeyFromMemory(keyBuff, passphrase);
  576. }
  577. keyCache.emplace(searchKey.str(), ret);
  578. }
  579. return LINK(ret);
  580. }
  581. };
  582. #else
  583. class CKeyCache : public CInterface
  584. {
  585. private:
  586. bool m_isPublic = false;
  587. StringAttr m_keyFS;
  588. StringAttr m_keyBuff;
  589. StringAttr m_passphrase;
  590. Owned<CLoadedKey> m_loadedKey;
  591. //String compare that treats null ptr and ptr to empty string as matching
  592. inline bool sameString(const char * left, const char * right)
  593. {
  594. if (isEmptyString(left))
  595. return isEmptyString(right);
  596. else if (isEmptyString(right))
  597. return false;
  598. return strcmp(left, right) == 0;
  599. }
  600. public:
  601. CLoadedKey * getInstance(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase, bool isLFN, IUserDescriptor * user)
  602. {
  603. if (!m_loadedKey ||
  604. isPublic != m_isPublic ||
  605. !sameString(passphrase, m_passphrase.str()) ||
  606. !sameString(keyFS, m_keyFS.str()) ||
  607. !sameString(keyBuff, m_keyBuff.str()))
  608. {
  609. CLoadedKey *newKey;
  610. if (!isEmptyString(keyFS))
  611. {
  612. if (isLFN)
  613. {
  614. StringBuffer sb;
  615. loadLFS(keyFS, user, sb);//read key file into StringBuffer
  616. if (isPublic)
  617. newKey = loadPublicKeyFromMemory(sb.str(), passphrase);
  618. else
  619. newKey = loadPrivateKeyFromMemory(sb.str(), passphrase);
  620. }
  621. else if (isPublic)
  622. newKey = loadPublicKeyFromFile(keyFS, passphrase);
  623. else
  624. newKey = loadPrivateKeyFromFile(keyFS, passphrase);
  625. }
  626. else if (!isEmptyString(keyBuff))
  627. {
  628. //Create CLoadedKey from key contents
  629. if (isPublic)
  630. newKey = loadPublicKeyFromMemory(keyBuff, passphrase);
  631. else
  632. newKey = loadPrivateKeyFromMemory(keyBuff, passphrase);
  633. }
  634. else
  635. throw makeStringException(-1, "Must specify a key filename or provide a key buffer");
  636. m_loadedKey.setown(newKey);//releases previous ptr
  637. m_isPublic = isPublic;
  638. m_keyFS.set(keyFS);
  639. m_keyBuff.set(keyBuff);
  640. m_passphrase.set(passphrase);
  641. }
  642. return LINK(m_loadedKey);
  643. }
  644. };
  645. #endif//_USE_HASHMAP
  646. //----------------------------------------------------------------------------
  647. // TLS storage of Key cache
  648. //----------------------------------------------------------------------------
  649. static thread_local CKeyCache *pKC = nullptr;
  650. static bool clearupKeyCache(bool isPooled)
  651. {
  652. delete pKC;
  653. pKC = nullptr;
  654. return false;
  655. }
  656. static CLoadedKey * getCachedKey(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase, bool isLFN, IUserDescriptor * udesc)
  657. {
  658. if (!pKC)
  659. {
  660. pKC = new CKeyCache();
  661. addThreadTermFunc(clearupKeyCache);
  662. }
  663. return pKC->getInstance(isPublic, keyFS, keyBuff, passphrase, isLFN, udesc);
  664. }
  665. //------------------------------------
  666. //Encryption helper
  667. //------------------------------------
  668. static void doPKIEncrypt(size32_t & __lenResult,void * & __result,
  669. CLoadedKey * publicKey,
  670. size32_t lenInputdata,const void * inputdata)
  671. {
  672. MemoryBuffer pkeMb;
  673. __lenResult = publicKeyEncrypt(pkeMb, lenInputdata, inputdata, *publicKey);
  674. if (__lenResult)
  675. {
  676. __result = CTXMALLOC(parentCtx, __lenResult);
  677. memcpy(__result, pkeMb.bytes(), __lenResult);
  678. }
  679. }
  680. //------------------------------------
  681. //Decryption helper
  682. //------------------------------------
  683. static void doPKIDecrypt(size32_t & __lenResult,void * & __result,
  684. CLoadedKey * privateKey,
  685. size32_t lenInputdata,const void * inputdata)
  686. {
  687. MemoryBuffer pkeMb;
  688. __lenResult = privateKeyDecrypt(pkeMb, lenInputdata, inputdata, *privateKey);
  689. if (__lenResult)
  690. {
  691. __result = CTXMALLOC(parentCtx, __lenResult);
  692. memcpy(__result, pkeMb.bytes(), __lenResult);
  693. }
  694. }
  695. //encryption functions that take filespecs of key files
  696. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncrypt(size32_t & __lenResult,void * & __result,
  697. const char * pkalgorithm,
  698. const char * publickeyfile,
  699. const char * passphrase,
  700. size32_t lenInputdata,const void * inputdata)
  701. {
  702. verifyPKIAlgorithm(pkalgorithm);
  703. Owned<CLoadedKey> publicKey = getCachedKey(true, publickeyfile, nullptr, passphrase, false, nullptr);
  704. doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
  705. }
  706. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecrypt(size32_t & __lenResult,void * & __result,
  707. const char * pkalgorithm,
  708. const char * privatekeyfile,
  709. const char * passphrase,
  710. size32_t lenEncrypteddata,const void * encrypteddata)
  711. {
  712. verifyPKIAlgorithm(pkalgorithm);
  713. Owned<CLoadedKey> privateKey = getCachedKey(false, privatekeyfile, nullptr, passphrase, false, nullptr);
  714. doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
  715. }
  716. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptLFN(ICodeContext * ctx,
  717. size32_t & __lenResult,void * & __result,
  718. const char * pkalgorithm,
  719. const char * publickeyLFN,
  720. const char * passphrase,
  721. size32_t lenInputdata,const void * inputdata)
  722. {
  723. verifyPKIAlgorithm(pkalgorithm);
  724. IUserDescriptor * udesc = ctx->queryUserDescriptor();
  725. Owned<CLoadedKey> publicKey = getCachedKey(true, publickeyLFN, nullptr, passphrase, true, udesc);
  726. doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
  727. }
  728. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptLFN(ICodeContext * ctx,
  729. size32_t & __lenResult,void * & __result,
  730. const char * pkalgorithm,
  731. const char * privatekeyLFN,
  732. const char * passphrase,
  733. size32_t lenEncrypteddata,const void * encrypteddata)
  734. {
  735. verifyPKIAlgorithm(pkalgorithm);
  736. IUserDescriptor * udesc = ctx->queryUserDescriptor();
  737. Owned<CLoadedKey> privateKey = getCachedKey(false, privatekeyLFN, nullptr, passphrase, true, udesc);
  738. doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
  739. }
  740. //encryption functions that take keys in a buffer
  741. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptBuff(size32_t & __lenResult,void * & __result,
  742. const char * pkalgorithm,
  743. const char * publickeybuff,
  744. const char * passphrase,
  745. size32_t lenInputdata,const void * inputdata)
  746. {
  747. verifyPKIAlgorithm(pkalgorithm);
  748. Owned<CLoadedKey> publicKey = getCachedKey(true, nullptr, publickeybuff, passphrase, false, nullptr);
  749. doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
  750. }
  751. CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptBuff(size32_t & __lenResult,void * & __result,
  752. const char * pkalgorithm,
  753. const char * privatekeybuff,
  754. const char * passphrase,
  755. size32_t lenEncrypteddata,const void * encrypteddata)
  756. {
  757. verifyPKIAlgorithm(pkalgorithm);
  758. Owned<CLoadedKey> privateKey = getCachedKey(false, nullptr, privatekeybuff, passphrase, false, nullptr);
  759. doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
  760. }