Skip to content
Snippets Groups Projects
rsa.cc 4.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <vereign/ncrypt/rsa.hh>
    
    #include <vereign/ncrypt/errors.hh>
    #include <vereign/core/string.hh>
    
    namespace vereign::ncrypt::rsa {
    
    auto OpenStorageProvider() -> UniquePtr {
      UniquePtr provider{};
      auto status = NCryptOpenStorageProvider(provider.Ref(), MS_KEY_STORAGE_PROVIDER, 0);
      if (status != ERROR_SUCCESS) {
        throw Error{status, "open crypto store failed"};
      }
    
      return provider;
    }
    
    auto LoadKey(NCRYPT_PROV_HANDLE provider, const std::string& key_name) -> UniquePtr {
      UniquePtr key{};
      auto wkey_name = string::widen(key_name);
      auto status = NCryptOpenKey(provider, key.Ref(), wkey_name.data(), 0, 0);
      if (status != ERROR_SUCCESS && status != NTE_BAD_KEYSET) {
        throw Error{status, "open key failed"};
      }
    
      return key;
    }
    
    
    auto CreateKey(
      NCRYPT_PROV_HANDLE provider,
      int bits,
      const std::string& key_name,
      std::optional<KeyUIPolicy> ui_policy
    ) -> UniquePtr {
    
      UniquePtr key{};
      auto wkey_name = string::widen(key_name);
      auto status = NCryptCreatePersistedKey(
        provider,
        key.Ref(),
        BCRYPT_RSA_ALGORITHM,
        wkey_name.data(),
        0,
        0
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "creating rsa key failed"};
      }
    
      auto key_len = DWORD(bits);
      status = NCryptSetProperty(
        key.Get(),
        NCRYPT_LENGTH_PROPERTY,
        (PBYTE)&key_len,
        sizeof(key_len),
        NCRYPT_PERSIST_FLAG
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "setup rsa key length failed"};
      }
    
    
      if (ui_policy) {
        auto creation_title = vereign::string::widen(ui_policy->CreationTitle);
        auto description = vereign::string::widen(ui_policy->Description);
        auto friendly_name = vereign::string::widen(ui_policy->FriendlyName);
    
        NCRYPT_UI_POLICY ui_policy_prop{};
        ui_policy_prop.dwVersion = 1;
        ui_policy_prop.dwFlags = NCRYPT_UI_PROTECT_KEY_FLAG;
        ui_policy_prop.pszCreationTitle = creation_title.data();
        ui_policy_prop.pszDescription = description.data();
        ui_policy_prop.pszFriendlyName = friendly_name.data();
    
        status = NCryptSetProperty(
          key.Get(),
          NCRYPT_UI_POLICY_PROPERTY,
          (PBYTE)&ui_policy_prop,
          sizeof(ui_policy_prop),
          NCRYPT_PERSIST_FLAG
        );
        if (status != ERROR_SUCCESS) {
          throw Error{status, "configure key ui policy failed"};
        }
      }
    
    
      status = NCryptFinalizeKey(key.Get(), 0);
      if (status != ERROR_SUCCESS) {
        throw Error{status, "finalizing rsa key failed"};
      }
    
      return key;
    }
    
    void DeleteKey(NCRYPT_KEY_HANDLE key) {
      auto status = NCryptDeleteKey(key, 0);
      if (status != ERROR_SUCCESS) {
        throw Error{status, "deleting key failed"};
      }
    }
    
    void PublicKeyEncrypt(NCRYPT_KEY_HANDLE key, bytes::View src, bytes::Buffer& encrypted) {
      BCRYPT_OAEP_PADDING_INFO pad;
      int flags = NCRYPT_PAD_OAEP_FLAG;
      pad.pszAlgId = BCRYPT_SHA1_ALGORITHM;
      pad.pbLabel = nullptr;
      pad.cbLabel = 0;
      DWORD size;
    
      auto status = NCryptEncrypt(
        key,
        (PBYTE)src.Data(),
        (DWORD)src.Size(),
        &pad,
        nullptr,
        0,
        &size,
        flags
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "encryption failed"};
      }
    
      encrypted.Reserve(size);
    
      status = NCryptEncrypt(
        key,
        (PBYTE)src.Data(),
        (DWORD)src.Size(),
        &pad,
        (PBYTE)encrypted.end(),
        size,
        &size,
        flags
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "encryption failed"};
      }
    
      encrypted.IncSize(size);
    }
    
    void PrivateKeyDecrypt(NCRYPT_KEY_HANDLE key, bytes::View src, bytes::Buffer& decrypted) {
      BCRYPT_OAEP_PADDING_INFO pad;
      int flags = NCRYPT_PAD_OAEP_FLAG;
      pad.pszAlgId = BCRYPT_SHA1_ALGORITHM;
      pad.pbLabel = nullptr;
      pad.cbLabel = 0;
      DWORD size;
    
      auto status = NCryptDecrypt(
        key,
        (PBYTE)src.Data(),
        (DWORD)src.Size(),
        &pad,
        nullptr,
        0,
        &size,
        flags
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "decryption failed"};
      }
    
      decrypted.Reserve(size);
    
      status = NCryptDecrypt(
        key,
        (PBYTE)src.Data(),
        (DWORD)src.Size(),
        &pad,
        (PBYTE)decrypted.end(),
        size,
        &size,
        flags
      );
      if (status != ERROR_SUCCESS) {
        throw Error{status, "decryption failed"};
      }
    
      decrypted.IncSize(size);
    }
    
    } // vereign::ncrypt::rsa