LCOV - code coverage report
Current view: top level - core/crypto - SPCrypto.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 424 491 86.4 %
Date: 2024-05-12 00:16:13 Functions: 77 77 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPCrypto.h"
      25             : #include "SPString.h"
      26             : #include "SPValid.h"
      27             : #include "SPMemory.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::crypto {
      30             : 
      31             : struct BackendCtx {
      32             :         static BackendCtx *get(Backend);
      33             : 
      34             :         Backend name;
      35             :         StringView title;
      36             :         BackendFlags flags;
      37             : 
      38             :         void (*initialize) () = nullptr;
      39             :         void (*finalize) () = nullptr;
      40             : 
      41             :         bool (*encryptBlock) (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) = nullptr;
      42             :         bool (*decryptBlock) (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) = nullptr;
      43             : 
      44             :         bool (*hash256) (Sha256::Buf &, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func);
      45             :         bool (*hash512) (Sha512::Buf &, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func);
      46             : 
      47             :         bool (*privInit) (KeyContext &ctx) = nullptr;
      48             :         void (*privFree) (KeyContext &ctx) = nullptr;
      49             : 
      50             :         bool (*privGen) (KeyContext &ctx, KeyBits, KeyType) = nullptr;
      51             :         bool (*privImport) (KeyContext &ctx, BytesView data, const CoderSource &passwd) = nullptr;
      52             :         bool (*privExportPem) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) = nullptr;
      53             :         bool (*privExportDer) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) = nullptr;
      54             :         bool (*privExportPublic) (KeyContext &target, const KeyContext &privKey) = nullptr;
      55             :         bool (*privSign) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) = nullptr;
      56             :         bool (*privVerify) (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) = nullptr;
      57             :         bool (*privEncrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
      58             :         bool (*privDecrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
      59             :         bool (*privFingerprint) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
      60             : 
      61             :         bool (*pubInit) (KeyContext &ctx) = nullptr;
      62             :         void (*pubFree) (KeyContext &ctx) = nullptr;
      63             : 
      64             :         bool (*pubImport) (KeyContext &ctx, BytesView data) = nullptr;
      65             :         bool (*pubImportOpenSSH) (KeyContext &ctx, StringView data) = nullptr;
      66             :         bool (*pubExportPem) (const KeyContext &ctx, const Callback<void(BytesView)> &cb) = nullptr;
      67             :         bool (*pubExportDer) (const KeyContext &ctx, const Callback<void(BytesView)> &cb) = nullptr;
      68             :         bool (*pubVerify) (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) = nullptr;
      69             :         bool (*pubEncrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
      70             : };
      71             : 
      72             : struct BackendCtxRef {
      73             :         static mem_std::HashMap<Backend, BackendCtx *> s_backends;
      74             : 
      75             :         BackendCtxRef(BackendCtx *);
      76             :         ~BackendCtxRef();
      77             : 
      78             :         BackendCtx *backend;
      79             : };
      80             : 
      81             : mem_std::HashMap<Backend, BackendCtx *> BackendCtxRef::s_backends;
      82             : 
      83        8625 : BackendCtx *BackendCtx::get(Backend b) {
      84        8625 :         auto it = BackendCtxRef::s_backends.find(b);
      85        8625 :         if (it !=  BackendCtxRef::s_backends.end()) {
      86        6575 :                 return it->second;
      87             :         }
      88             : 
      89        2050 :         if (b == Backend::Default) {
      90        1800 :                 BackendCtx *ret = nullptr;
      91             : #if MODULE_STAPPLER_CRYPTO_GNUTLS
      92        1800 :                 if (!ret) {
      93        1800 :                         ret = get(Backend::GnuTLS);
      94             :                 }
      95             : #endif
      96             : #if MODULE_STAPPLER_CRYPTO_OPENSSL
      97        1800 :                 if (!ret) {
      98           0 :                         ret = get(Backend::OpenSSL);
      99             :                 }
     100             : #endif
     101             : #if MODULE_STAPPLER_CRYPTO_MBEDTLS
     102        1800 :                 if (!ret) {
     103           0 :                         ret = get(Backend::MbedTLS);
     104             :                 }
     105             : #endif
     106        1800 :                 if (!ret) {
     107           0 :                         ret = get(Backend::Embedded);
     108             :                 }
     109        1800 :                 return ret;
     110             :         }
     111             : 
     112         250 :         return nullptr;
     113             : }
     114             : 
     115          75 : BackendCtxRef::BackendCtxRef(BackendCtx *ctx) {
     116          75 :         s_backends.emplace(ctx->name, ctx);
     117          75 :         backend = ctx;
     118          75 :         if (backend->initialize) {
     119          75 :                 backend->initialize();
     120             :         }
     121          75 : }
     122             : 
     123          75 : BackendCtxRef::~BackendCtxRef() {
     124          75 :         s_backends.erase(backend->name);
     125          75 :         if (backend->finalize) {
     126          75 :                 backend->finalize();
     127             :         }
     128          75 : }
     129             : 
     130          25 : void listBackends(const Callback<void(Backend, StringView, BackendFlags)> &cb) {
     131         100 :         for (auto &it : BackendCtxRef::s_backends) {
     132          75 :                 cb(it.first, it.second->title, it.second->flags);
     133             :         }
     134          25 : }
     135             : 
     136        2475 : bool isPemKey(BytesView data) {
     137        2475 :         StringView str(reinterpret_cast<const char *>(data.data()), data.size());
     138        2475 :         str.skipUntilString("-----");
     139        2475 :         if (str.is("-----")) {
     140        1100 :                 return true;
     141             :         }
     142        1375 :         return false;
     143             : }
     144             : 
     145         400 : static bool isBackendValidForBlock(BackendCtx *b, BlockCipher c) {
     146         400 :         switch (c) {
     147         200 :         case BlockCipher::AES_CBC:
     148             :         case BlockCipher::AES_CFB8:
     149         200 :                 if ((b->flags & BackendFlags::SupportsAes) != BackendFlags::None && b->encryptBlock && b->decryptBlock) {
     150         200 :                         return true;
     151             :                 }
     152           0 :                 break;
     153         200 :         case BlockCipher::Gost3412_2015_CTR_ACPKM:
     154         200 :                 if ((b->flags & BackendFlags::SupportsGost3412_2015) != BackendFlags::None && b->encryptBlock && b->decryptBlock) {
     155         200 :                         return true;
     156             :                 }
     157           0 :                 break;
     158             :         }
     159           0 :         return false;
     160             : }
     161             : 
     162         400 : static BackendCtx *findBackendForBlock(BlockCipher c) {
     163             :         // check default
     164             : 
     165         400 :         auto check = [&] (BackendCtx *b, bool secure) -> BackendCtx * {
     166         400 :                 if (b && (b->flags & BackendFlags::SecureLibrary) == (secure ? BackendFlags::SecureLibrary : BackendFlags::None)) {
     167         400 :                         if (isBackendValidForBlock(b, c)) {
     168         400 :                                 return b;
     169             :                         }
     170             :                 }
     171           0 :                 return nullptr;
     172         400 :         };
     173             : 
     174         400 :         auto b = check(BackendCtx::get(Backend::Default), true);
     175         400 :         if (b) {
     176         400 :                 return b;
     177             :         }
     178             : 
     179             :         // check secure libs first
     180           0 :         for (auto &it : BackendCtxRef::s_backends) {
     181           0 :                 if (check(it.second, true)) { return it.second; }
     182             :         }
     183             : 
     184           0 :         for (auto &it : BackendCtxRef::s_backends) {
     185           0 :                 if (check(it.second, false)) { return it.second; }
     186             :         }
     187           0 :         return nullptr;
     188             : }
     189             : 
     190         525 : static void fillCryptoBlockHeader(uint8_t *buf, const BlockKey256 &key, BytesView d) {
     191         525 :         uint64_t dataSize = d.size();
     192             : 
     193             :         BlockCryptoHeader header;
     194         525 :         header.size = byteorder::HostToLittle(dataSize);
     195         525 :         header.version = byteorder::HostToLittle(key.version);
     196         525 :         header.cipher = byteorder::HostToLittle(toInt(key.cipher));
     197         525 :         header.padding = 0;
     198             : 
     199         525 :         memcpy(buf, &header, sizeof(BlockCryptoHeader));
     200         525 : }
     201             : 
     202         650 : static SignAlgorithm getSignForBlockCipher(const PrivateKey &key) {
     203         650 :         switch (key.getType()) {
     204          50 :         case KeyType::GOST3410_2012_256:
     205          50 :                 return SignAlgorithm::GOST_256;
     206             :                 break;
     207          50 :         case KeyType::GOST3410_2012_512:
     208          50 :                 return SignAlgorithm::GOST_512;
     209             :                 break;
     210         550 :         default:
     211         550 :                 break;
     212             :         }
     213         550 :         return SignAlgorithm::RSA_SHA512;
     214             : }
     215             : 
     216         275 : bool encryptBlock(const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
     217         275 :         auto b = findBackendForBlock(key.cipher);
     218         275 :         return b->encryptBlock(key, data, cb);
     219             : }
     220             : 
     221         175 : bool encryptBlock(Backend b, const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
     222         175 :         auto backend = BackendCtx::get(b);
     223         175 :         if (!backend || !backend->encryptBlock) {
     224           0 :                 return false;
     225             :         }
     226         175 :         return backend->encryptBlock(key, data, cb);
     227             : }
     228             : 
     229         125 : bool decryptBlock(const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
     230         125 :         auto b = findBackendForBlock(key.cipher);
     231         125 :         return b->decryptBlock(key, data, cb);
     232             : }
     233             : 
     234         400 : bool decryptBlock(Backend b, const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
     235         400 :         auto backend = BackendCtx::get(b);
     236         400 :         if (!backend || !backend->decryptBlock) {
     237           0 :                 return false;
     238             :         }
     239         400 :         return backend->decryptBlock(key, data, cb);
     240             : }
     241             : 
     242         225 : BlockKey256 makeBlockKey(Backend b, BytesView pkey, BytesView hash, BlockCipher c, uint32_t version) {
     243         225 :         crypto::PrivateKey pk(b, pkey);
     244         225 :         if (pk && version > 0) {
     245          75 :                 auto ret = makeBlockKey(pk, hash, c, version);
     246          75 :                 if (ret.version == 0) {
     247           0 :                         ret.data = string::Sha256().update(hash).update(pkey).final();
     248             :                 }
     249          75 :                 ret.cipher = c;
     250          75 :                 return ret;
     251             :         } else {
     252         300 :                 return BlockKey256 { 0, c, string::Sha256().update(hash).update(pkey).final() };
     253             :         }
     254         225 : }
     255             : 
     256         225 : BlockKey256 makeBlockKey(BytesView pkey, BytesView hash, BlockCipher b, uint32_t version) {
     257         225 :         return makeBlockKey(Backend::Default, pkey, hash, b, version);
     258             : }
     259             : 
     260         525 : BlockKey256 makeBlockKey(const PrivateKey &pkey, BytesView hash, uint32_t version) {
     261         525 :         switch (pkey.getType()) {
     262         200 :         case KeyType::GOST3410_2012_256:
     263             :         case KeyType::GOST3410_2012_512:
     264         200 :                 return makeBlockKey(pkey, hash, BlockCipher::Gost3412_2015_CTR_ACPKM, version);
     265             :                 break;
     266         325 :         default:
     267         325 :                 break;
     268             :         }
     269         325 :         return makeBlockKey(pkey, hash, BlockCipher::AES_CBC, version);
     270             : }
     271             : 
     272        1050 : BlockKey256 makeBlockKey(const PrivateKey &pkey, BytesView hash, BlockCipher b, uint32_t version) {
     273        1050 :         BlockKey256 ret;
     274        1050 :         ret.cipher = b;
     275        1050 :         if (version == 2) {
     276         875 :                 ret.version = 0;
     277         875 :                 switch (b) {
     278         475 :                 case BlockCipher::AES_CBC:
     279             :                 case BlockCipher::AES_CFB8:
     280         475 :                         pkey.sign([&] (BytesView data) {
     281         950 :                                 ret.version = version;
     282         475 :                                 ret.data = hash256(pkey.getBackend(), CoderSource(data), HashFunction::SHA_2);
     283         475 :                         }, hash, getSignForBlockCipher(pkey));
     284         475 :                         break;
     285         400 :                 case BlockCipher::Gost3412_2015_CTR_ACPKM:
     286         400 :                         pkey.fingerprint([&] (BytesView data) {
     287         800 :                                 ret.version = version;
     288         400 :                                 ret.data = Gost3411_256::hmac(hash, data);
     289         400 :                         }, hash);
     290         400 :                         break;
     291             :                 }
     292         175 :         } else if (version == 1) {
     293         175 :                 if (!pkey.sign([&] (BytesView data) {
     294         175 :                         auto s = std::min(data.size(), size_t(256));
     295         175 :                         ret.data = hash256(pkey.getBackend(), CoderSource(BytesView(data, s)), HashFunction::SHA_2);
     296         175 :                         ret.version = version;
     297         175 :                 }, hash, getSignForBlockCipher(pkey))) {
     298           0 :                         ret.version = 0;
     299             :                 }
     300             :         } else {
     301           0 :                 ret.version = 0;
     302             :         }
     303        1050 :         return ret;
     304             : }
     305             : 
     306         650 : BlockInfo getBlockInfo(BytesView val) {
     307         650 :         BlockInfo ret;
     308         650 :         BytesViewTemplate<Endian::Little> b(val);
     309         650 :         ret.dataSize = b.readUnsigned64();
     310         650 :         ret.version = b.readUnsigned16();
     311         650 :         ret.cipher = BlockCipher(b.readUnsigned16());
     312         650 :         return ret;
     313             : }
     314             : 
     315        1250 : Sha256::Buf hash256(Backend b, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) {
     316         125 :         auto embedded = [&] {
     317         125 :                 switch (func) {
     318          25 :                 case HashFunction::SHA_2: {
     319          25 :                         Sha256 ctx;
     320          25 :                         cb([&] (const CoderSource &data) {
     321          25 :                                 ctx.update(data);
     322          25 :                                 return true;
     323             :                         });
     324          25 :                         return ctx.final();
     325             :                         break;
     326             :                 }
     327         100 :                 case HashFunction::GOST_3411:
     328         100 :                         Gost3411_256 ctx;
     329         100 :                         cb([&] (const CoderSource &data) {
     330         100 :                                 ctx.update(data);
     331         100 :                                 return true;
     332             :                         });
     333         100 :                         return ctx.final();
     334             :                         break;
     335             :                 }
     336           0 :                 return Sha256::Buf();
     337        1250 :         };
     338             : 
     339        1250 :         auto bctx = BackendCtx::get(b);
     340        1250 :         if (!bctx) {
     341         125 :                 return embedded();
     342             :         } else {
     343             :                 Sha256::Buf ctx;
     344        1125 :                 if (!bctx->hash256 || !bctx->hash256(ctx, cb, func)) {
     345           0 :                         return embedded();
     346             :                 }
     347        1125 :                 return ctx;
     348             :         }
     349             : }
     350             : 
     351        1150 : Sha256::Buf hash256(Backend b, const CoderSource &data, HashFunction func) {
     352        2300 :         return hash256(b, Callback<void( const HashCoderCallback &upd )>([&] (const HashCoderCallback &upd) {
     353        1150 :                 upd(data);
     354        2300 :         }), func);
     355             : }
     356             : 
     357         900 : Sha512::Buf hash512(Backend b, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) {
     358         125 :         auto embedded = [&] {
     359         125 :                 switch (func) {
     360          25 :                 case HashFunction::SHA_2: {
     361          25 :                         Sha512 ctx;
     362          25 :                         cb([&] (const CoderSource &data) {
     363          25 :                                 ctx.update(data);
     364          25 :                                 return true;
     365             :                         });
     366          25 :                         return ctx.final();
     367             :                         break;
     368             :                 }
     369         100 :                 case HashFunction::GOST_3411:
     370         100 :                         Gost3411_512 ctx;
     371         100 :                         cb([&] (const CoderSource &data) {
     372         100 :                                 ctx.update(data);
     373         100 :                                 return true;
     374             :                         });
     375         100 :                         return ctx.final();
     376             :                         break;
     377             :                 }
     378           0 :                 return Sha512::Buf();
     379         900 :         };
     380             : 
     381         900 :         auto bctx = BackendCtx::get(b);
     382         900 :         if (!bctx) {
     383         125 :                 return embedded();
     384             :         } else {
     385             :                 Sha512::Buf ctx;
     386         775 :                 if (!bctx->hash512 || !bctx->hash512(ctx, cb, func)) {
     387           0 :                         return embedded();
     388             :                 }
     389         775 :                 return ctx;
     390             :         }
     391             : }
     392             : 
     393         500 : Sha512::Buf hash512(Backend b, const CoderSource &data, HashFunction func) {
     394        1000 :         return hash512(b, Callback<void( const HashCoderCallback &upd )>([&] (const HashCoderCallback &upd) {
     395         500 :                 upd(data);
     396        1000 :         }), func);
     397             : }
     398             : 
     399         100 : Sha256::Buf hash256(const Callback<void( const Callback<bool(const CoderSource &)> &upd )> &cb, HashFunction func) {
     400         100 :         return hash256(Backend::Default, cb, func);
     401             : }
     402         100 : Sha256::Buf hash256(const CoderSource &data, HashFunction func) {
     403         100 :         return hash256(Backend::Default, data, func);
     404             : }
     405             : 
     406         400 : Sha512::Buf hash512(const Callback<void( const Callback<bool(const CoderSource &)> &upd )> &cb, HashFunction func) {
     407         400 :         return hash512(Backend::Default, cb, func);
     408             : }
     409         100 : Sha512::Buf hash512(const CoderSource &data, HashFunction func) {
     410         100 :         return hash512(Backend::Default, data, func);
     411             : }
     412             : 
     413        2425 : PrivateKey::PrivateKey(Backend b) : _valid(true), _key() {
     414        2425 :         auto backend = BackendCtx::get(b);
     415        2425 :         if (!backend) {
     416           0 :                 _valid = false;
     417           0 :                 return;
     418             :         }
     419             : 
     420        2425 :         if (!backend->privInit || !backend->privInit(_key)) {
     421           0 :                 _valid = false;
     422             :         }
     423             : 
     424        2425 :         _key.backendCtx = backend;
     425             : }
     426             : 
     427        1200 : PrivateKey::PrivateKey(Backend b, BytesView data, const CoderSource &str) : PrivateKey(b) {
     428        1200 :         this->import(data, str);
     429        1200 : }
     430             : 
     431         200 : PrivateKey::PrivateKey(BytesView data, const CoderSource &str) : PrivateKey(Backend::Default) {
     432         200 :         this->import(data, str);
     433         200 : }
     434             : 
     435        2450 : PrivateKey::~PrivateKey() {
     436        2450 :         if (_valid) {
     437        2350 :                 auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     438        2350 :                 if (backend && backend->privFree) {
     439        2350 :                         backend->privFree(_key);
     440        2350 :                         _valid = false;
     441             :                 }
     442             :         }
     443        2450 : }
     444             : 
     445          50 : PrivateKey::PrivateKey(PrivateKey &&other) {
     446          50 :         _key = other._key;
     447          50 :         _valid = other._valid;
     448          50 :         _loaded = other._loaded;
     449             : 
     450          50 :         other._valid = false;
     451          50 :         other._loaded = false;
     452          50 :         other._key.cryptoCtx = nullptr;
     453          50 :         other._key.keyCtx = nullptr;
     454          50 :         other._key.backendCtx = nullptr;
     455          50 : }
     456             : 
     457          50 : PrivateKey& PrivateKey::operator=(PrivateKey &&other) {
     458          50 :         if (_valid) {
     459          50 :                 auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     460          50 :                 if (backend && backend->privFree) {
     461          50 :                         backend->privFree(_key);
     462          50 :                         _valid = false;
     463             :                 }
     464             :         }
     465             : 
     466          50 :         _key = other._key;
     467          50 :         _valid = other._valid;
     468          50 :         _loaded = other._loaded;
     469             : 
     470          50 :         other._valid = false;
     471          50 :         other._loaded = false;
     472          50 :         other._key.cryptoCtx = nullptr;
     473          50 :         other._key.keyCtx = nullptr;
     474          50 :         other._key.backendCtx = nullptr;
     475          50 :         return *this;
     476             : }
     477             : 
     478         200 : bool PrivateKey::generate(KeyType type) {
     479         200 :         return generate(KeyBits::_4096, type);
     480             : }
     481             : 
     482         725 : bool PrivateKey::generate(KeyBits bits, KeyType type) {
     483         725 :         if (!_valid) {
     484           0 :                 return false;
     485             :         }
     486             : 
     487         725 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     488         725 :         if (backend && backend->privGen && backend->privGen(_key, bits, type)) {
     489         725 :                 _loaded = true;
     490         725 :                 return true;
     491             :         }
     492             : 
     493           0 :         return false;
     494             : }
     495             : 
     496        1475 : bool PrivateKey::import(BytesView data, const CoderSource &passwd) {
     497        1475 :         if (_loaded || !_valid || data.empty()) {
     498           0 :                 return false;
     499             :         }
     500             : 
     501        1475 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     502        1475 :         if (backend && backend->privImport && backend->privImport(_key, data, passwd)) {
     503        1300 :                 _loaded = true;
     504        1300 :                 return true;
     505             :         }
     506             : 
     507         175 :         return false;
     508             : }
     509             : 
     510         300 : PublicKey PrivateKey::exportPublic() const {
     511         300 :         return PublicKey(*this);
     512             : }
     513             : 
     514         650 : Backend PrivateKey::getBackend() const {
     515         650 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     516         650 :         return backend->name;
     517             : }
     518             : 
     519         850 : bool PrivateKey::exportPem(const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) const {
     520         850 :         if (!_loaded || !_valid) {
     521           0 :                 return false;
     522             :         }
     523             : 
     524         850 :         if (fmt == KeyFormat::RSA && getType() != KeyType::RSA) {
     525           0 :                 log::error("Crypto", "Unable to export non-RSA key in PKCS#1 format");
     526           0 :                 return false;
     527             :         }
     528             : 
     529         850 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     530         850 :         if (backend && backend->privExportPem && backend->privExportPem(_key, cb, fmt, passPhrase)) {
     531         850 :                 return true;
     532             :         }
     533             : 
     534           0 :         return false;
     535             : }
     536             : 
     537         150 : bool PrivateKey::exportPem(const Callback<void(BytesView)> &cb, const CoderSource &passPhrase) const {
     538         150 :         return exportPem(cb, KeyFormat::PKCS8, passPhrase);
     539             : }
     540             : 
     541         900 : bool PrivateKey::exportDer(const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) const {
     542         900 :         if (!_loaded || !_valid) {
     543           0 :                 return false;
     544             :         }
     545             : 
     546         900 :         if (fmt == KeyFormat::RSA && getType() != KeyType::RSA) {
     547           0 :                 log::error("Crypto", "Unable to export non-RSA key in PKCS#1 format");
     548           0 :                 return false;
     549             :         }
     550             : 
     551         900 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     552         900 :         if (backend && backend->privExportDer && backend->privExportDer(_key, cb, fmt, passPhrase)) {
     553         900 :                 return true;
     554             :         }
     555             : 
     556           0 :         return false;
     557             : }
     558             : 
     559         150 : bool PrivateKey::exportDer(const Callback<void(BytesView)> &cb, const CoderSource &passPhrase) const {
     560         150 :         return exportDer(cb, KeyFormat::PKCS8, passPhrase);
     561             : }
     562             : 
     563        1175 : bool PrivateKey::sign(const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) const {
     564        1175 :         if (!_loaded || !_valid) {
     565           0 :                 return false;
     566             :         }
     567             : 
     568        1175 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     569        1175 :         if (backend && backend->privSign && backend->privSign(_key, cb, data, algo)) {
     570        1175 :                 return true;
     571             :         }
     572             : 
     573           0 :         return false;
     574             : }
     575             : 
     576         425 : bool PrivateKey::verify(const CoderSource &data, BytesView signature, SignAlgorithm algo) const {
     577         425 :         if (!_loaded || !_valid) {
     578           0 :                 return false;
     579             :         }
     580             : 
     581         425 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     582         425 :         if (backend && backend->privVerify && backend->privVerify(_key, data, signature, algo)) {
     583         425 :                 return true;
     584             :         }
     585             : 
     586           0 :         return false;
     587             : }
     588             : 
     589         575 : bool PrivateKey::fingerprint(const Callback<void(BytesView)> &cb, const CoderSource &data) const {
     590         575 :         if (!_loaded || !_valid) {
     591           0 :                 return false;
     592             :         }
     593             : 
     594         575 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     595         575 :         if (backend && backend->privFingerprint && backend->privFingerprint(_key, cb, data)) {
     596         575 :                 return true;
     597             :         }
     598             : 
     599           0 :         return false;
     600             : }
     601             : 
     602         225 : bool PrivateKey::isGenerateSupported(KeyType type) const {
     603         225 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     604         225 :         switch (type) {
     605          75 :         case KeyType::RSA:
     606          75 :                 return (backend->flags & BackendFlags::SecureLibrary) != BackendFlags::None;
     607             :                 break;
     608         150 :         case KeyType::GOST3410_2012_256:
     609             :         case KeyType::GOST3410_2012_512:
     610         150 :                 return (backend->flags & BackendFlags::SupportsGost3410_2012) != BackendFlags::None;
     611             :                 break;
     612             : 
     613           0 :         case KeyType::Unknown:
     614             :         case KeyType::DSA:
     615             :         case KeyType::ECDSA:
     616             :         case KeyType::EDDSA_ED448:
     617           0 :                 return false;
     618             :                 break;
     619             :         }
     620           0 :         return false;
     621             : }
     622             : 
     623         550 : bool PrivateKey::isSupported(KeyFormat fmt) const {
     624         550 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     625         550 :         switch (fmt) {
     626         225 :         case KeyFormat::PKCS1: return (backend->flags & BackendFlags::SupportsPKCS1) != BackendFlags::None; break;
     627         325 :         case KeyFormat::PKCS8: return (backend->flags & BackendFlags::SupportsPKCS8) != BackendFlags::None; break;
     628             :         }
     629           0 :         return false;
     630             : }
     631             : 
     632         275 : bool PrivateKey::encrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
     633         275 :         if (!_loaded || !_valid) {
     634           0 :                 return false;
     635             :         }
     636             : 
     637         275 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     638         275 :         if (backend && backend->privEncrypt) {
     639         275 :                 return backend->privEncrypt(_key, cb, data);
     640             :         }
     641             : 
     642           0 :         return false;
     643             : }
     644             : 
     645         150 : bool PrivateKey::decrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
     646         150 :         if (!_loaded || !_valid) {
     647           0 :                 return false;
     648             :         }
     649             : 
     650         150 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     651         150 :         if (backend && backend->privDecrypt) {
     652         150 :                 return backend->privDecrypt(_key, cb, data);
     653             :         }
     654             : 
     655           0 :         return false;
     656             : }
     657             : 
     658        1275 : PublicKey::PublicKey(Backend b) : _valid(true), _key() {
     659        1275 :         auto backend = BackendCtx::get(b);
     660        1275 :         if (!backend) {
     661           0 :                 _valid = false;
     662           0 :                 return;
     663             :         }
     664             : 
     665        1275 :         if (!backend->pubInit || !backend->pubInit(_key)) {
     666           0 :                 _valid = false;
     667             :         }
     668        1275 :         _key.backendCtx = backend;
     669             : }
     670             : 
     671        1000 : PublicKey::PublicKey(Backend b, BytesView data) : PublicKey(b) {
     672        1000 :         if (data.starts_with(reinterpret_cast<const uint8_t *>("ssh-rsa"), "ssh-rsa"_len)) {
     673          75 :                 importOpenSSH(StringView(reinterpret_cast<const char *>(data.data()), data.size()));
     674             :         } else {
     675         925 :                 this->import(data);
     676             :         }
     677        1000 : }
     678             : 
     679         100 : PublicKey::PublicKey(BytesView data) : PublicKey(Backend::Default) {
     680         100 :         if (data.starts_with(reinterpret_cast<const uint8_t *>("ssh-rsa"), "ssh-rsa"_len)) {
     681          25 :                 importOpenSSH(StringView(reinterpret_cast<const char *>(data.data()), data.size()));
     682             :         } else {
     683          75 :                 this->import(data);
     684             :         }
     685         100 : }
     686             : 
     687         475 : PublicKey::PublicKey(const PrivateKey &priv) : _valid(false) {
     688         475 :         auto backend = static_cast<BackendCtx *>(priv.getKey().backendCtx);
     689         475 :         if (backend && backend->privExportPublic && backend->privExportPublic(_key, priv.getKey())) {
     690         475 :                 _valid = true;
     691         475 :                 _loaded = true;
     692         475 :                 _key.backendCtx = priv.getKey().backendCtx;
     693             :         }
     694         475 : }
     695             : 
     696        1800 : PublicKey::~PublicKey() {
     697        1800 :         if (_valid) {
     698        1650 :                 auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     699        1650 :                 if (backend && backend->pubFree) {
     700        1650 :                         backend->pubFree(_key);
     701        1650 :                         _valid = false;
     702             :                 }
     703             :         }
     704        1800 : }
     705             : 
     706          75 : PublicKey::PublicKey(PublicKey &&other) {
     707          75 :         _key = other._key;
     708          75 :         _valid = other._valid;
     709          75 :         _loaded = other._loaded;
     710             : 
     711          75 :         other._valid = false;
     712          75 :         other._loaded = false;
     713          75 :         other._key.cryptoCtx = nullptr;
     714          75 :         other._key.keyCtx = nullptr;
     715          75 :         other._key.backendCtx = nullptr;
     716          75 : }
     717             : 
     718          75 : PublicKey& PublicKey::operator=(PublicKey &&other) {
     719          75 :         if (_valid) {
     720          75 :                 auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     721          75 :                 if (backend && backend->pubFree) {
     722          75 :                         backend->pubFree(_key);
     723          75 :                         _valid = false;
     724             :                 }
     725             :         }
     726             : 
     727          75 :         _key = other._key;
     728          75 :         _valid = other._valid;
     729          75 :         _loaded = other._loaded;
     730             : 
     731          75 :         other._valid = false;
     732          75 :         other._loaded = false;
     733          75 :         other._key.cryptoCtx = nullptr;
     734          75 :         other._key.keyCtx = nullptr;
     735          75 :         other._key.backendCtx = nullptr;
     736          75 :         return *this;
     737             : }
     738             : 
     739        1000 : bool PublicKey::import(BytesView data) {
     740        1000 :         if (_loaded || !_valid || data.empty()) {
     741           0 :                 return false;
     742             :         }
     743             : 
     744        1000 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     745        1000 :         if (backend && backend->pubImport && backend->pubImport(_key, data)) {
     746        1000 :                 _loaded = true;
     747        1000 :                 return true;
     748             :         }
     749             : 
     750           0 :         return false;
     751             : }
     752             : 
     753         175 : bool PublicKey::importOpenSSH(StringView r) {
     754         175 :         if (!_valid || _loaded) {
     755           0 :                 return false;
     756             :         }
     757             : 
     758         175 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     759         175 :         if (backend && backend->pubImportOpenSSH && backend->pubImportOpenSSH(_key, r)) {
     760         175 :                 _loaded = true;
     761         175 :                 return true;
     762             :         }
     763             : 
     764           0 :         return false;
     765             : }
     766             : 
     767          75 : Backend PublicKey::getBackend() const {
     768          75 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     769          75 :         return backend->name;
     770             : }
     771             : 
     772         550 : bool PublicKey::exportPem(const Callback<void(BytesView)> &cb) const {
     773         550 :         if (!_loaded || !_valid) {
     774           0 :                 return false;
     775             :         }
     776             : 
     777         550 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     778         550 :         if (backend && backend->pubExportPem && backend->pubExportPem(_key, cb)) {
     779         550 :                 return true;
     780             :         }
     781             : 
     782           0 :         return false;
     783             : }
     784             : 
     785         650 : bool PublicKey::exportDer(const Callback<void(BytesView)> &cb) const {
     786         650 :         if (!_loaded || !_valid) {
     787           0 :                 return false;
     788             :         }
     789             : 
     790         650 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     791         650 :         if (backend && backend->pubExportDer && backend->pubExportDer(_key, cb)) {
     792         650 :                 return true;
     793             :         }
     794             : 
     795           0 :         return false;
     796             : }
     797             : 
     798         625 : bool PublicKey::verify(const CoderSource &data, BytesView signature, SignAlgorithm algo) const {
     799         625 :         if (!_loaded || !_valid) {
     800           0 :                 return false;
     801             :         }
     802             : 
     803         625 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     804         625 :         if (backend && backend->pubVerify && backend->pubVerify(_key, data, signature, algo)) {
     805         625 :                 return true;
     806             :         }
     807             : 
     808           0 :         return false;
     809             : }
     810             : 
     811         375 : bool PublicKey::encrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
     812         375 :         if (!_loaded || !_valid) {
     813           0 :                 return false;
     814             :         }
     815             : 
     816         375 :         auto backend = static_cast<BackendCtx *>(_key.backendCtx);
     817         375 :         if (backend && backend->pubEncrypt) {
     818         375 :                 return backend->pubEncrypt(_key, cb, data);
     819             :         }
     820             : 
     821           0 :         return false;
     822             : }
     823             : 
     824         100 : static uint8_t * writeRSAKey(uint8_t *buf, BytesViewNetwork mod, BytesViewNetwork exp) {
     825         100 :         size_t modSize = 1;
     826         100 :         size_t expSize = 1;
     827             : 
     828         200 :         auto readSize = [&] (size_t s) {
     829         200 :                 if (s < 128) {
     830         100 :                         return 1;
     831         100 :                 } else if (s < 256) {
     832           0 :                         return 2;
     833             :                 } else {
     834         100 :                         return 3;
     835             :                 }
     836             :         };
     837             : 
     838         300 :         auto writeSize = [&] (size_t s) {
     839         300 :                 if (s < 128) {
     840         100 :                         *buf = uint8_t(s); ++ buf;
     841         200 :                 } else if (s < 256) {
     842           0 :                         *buf = uint8_t(0x81); ++ buf;
     843           0 :                         *buf = uint8_t(s); ++ buf;
     844             :                 } else {
     845         200 :                         *buf = uint8_t(0x82); ++ buf;
     846         200 :                         *buf = uint8_t((s >> 8) & 0xFF); ++ buf;
     847         200 :                         *buf = uint8_t(s & 0xFF); ++ buf;
     848             :                 }
     849         400 :         };
     850             : 
     851         100 :         modSize += readSize(mod.size()) + mod.size();
     852         100 :         expSize += readSize(exp.size()) + exp.size();
     853             : 
     854         100 :         *buf = uint8_t(0x30); ++ buf;
     855         100 :         writeSize(modSize + expSize);
     856             : 
     857         100 :         *buf = uint8_t(0x02); ++ buf;
     858         100 :         writeSize(mod.size());
     859       38600 :         for (size_t i = 0; i < mod.size(); ++ i) {
     860       38500 :                 *buf = mod.at(i); ++ buf;
     861             :         }
     862             : 
     863         100 :         *buf = uint8_t(0x02); ++ buf;
     864         100 :         writeSize(exp.size());
     865         400 :         for (size_t i = 0; i < exp.size(); ++ i) {
     866         300 :                 *buf = exp.at(i); ++ buf;
     867             :         }
     868             : 
     869         100 :         return buf;
     870             : }
     871             : 
     872             : }
     873             : 
     874             : #ifdef __LCC__
     875             : #pragma diag_suppress 2464
     876             : #pragma diag_suppress 1444
     877             : #endif
     878             : 
     879             : #include "SPCrypto-openssl.cc"
     880             : #include "SPCrypto-mbedtls.cc"
     881             : #include "SPCrypto-gnutls.cc"
     882             : 
     883             : #ifdef __LCC__
     884             : #pragma diag_default 2464
     885             : #pragma diag_default 1444
     886             : #endif

Generated by: LCOV version 1.14