/*++ Module Name: PGP.cpp Notices: PGP library Author: Copyright (c) Prepodobny Alen mailto: alienufo@inbox.ru mailto: ufocomp@gmail.com --*/ #include "Core.hpp" #include "PGP.hpp" //---------------------------------------------------------------------------------------------------------------------- #include //---------------------------------------------------------------------------------------------------------------------- extern "C++" { namespace Apostol { namespace PGP { const std::map Public_Key_Type = { std::make_pair(Packet::SECRET_KEY, "sec"), std::make_pair(Packet::PUBLIC_KEY, "pub"), std::make_pair(Packet::SECRET_SUBKEY, "ssb"), std::make_pair(Packet::PUBLIC_SUBKEY, "sub"), }; //-------------------------------------------------------------------------------------------------------------- //-- Key::Key -------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- Key::Key(): OpenPGP::Key() { } //-------------------------------------------------------------------------------------------------------------- Key::Key(const OpenPGP::PGP ©): OpenPGP::Key(copy) { } //-------------------------------------------------------------------------------------------------------------- Key::Key(const Key ©): OpenPGP::Key(copy) { } //-------------------------------------------------------------------------------------------------------------- Key::Key(const std::string &data): OpenPGP::Key(data) { } //-------------------------------------------------------------------------------------------------------------- Key::Key(std::istream &stream): OpenPGP::Key(stream) { } //-------------------------------------------------------------------------------------------------------------- std::string Key::ListKeys(std::size_t indents, std::size_t indent_size) const { if (!meaningful()) { return "Key data not meaningful."; } const std::string indent(indents * indent_size, ' '); // print Key and User packets std::stringstream out; for (Packet::Tag::Ptr const & p : packets) { // primary key/subkey if (Packet::is_key_packet(p -> get_tag())) { const Packet::Key::Ptr key = std::static_pointer_cast (p); if (Packet::is_subkey(p -> get_tag())) { out << "\n"; } out << indent << Apostol::PGP::Public_Key_Type.at(p -> get_tag()) << " " << std::setfill(' ') << std::setw(4) << std::to_string(bitsize(key -> get_mpi()[0])) << indent << PKA::SHORT.at(key -> get_pka()) << "/" << indent << hexlify(key -> get_keyid()) << " " << indent << show_date(key -> get_time()); } // User ID else if (p -> get_tag() == Packet::USER_ID) { out << "\n" << indent << "uid " << std::static_pointer_cast (p) -> get_contents(); } // User Attribute else if (p -> get_tag() == Packet::USER_ATTRIBUTE) { for(Subpacket::Tag17::Sub::Ptr const & s : std::static_pointer_cast (p) -> get_attributes()) { // since only subpacket type 1 is defined out << "\n" << indent << "att att [jpeg image of size " << std::static_pointer_cast (s) -> get_image().size() << "]"; } } // Signature else if (p -> get_tag() == Packet::SIGNATURE) { out << indent << "sig "; const Packet::Tag2::Ptr sig = std::static_pointer_cast (p); if (Signature_Type::is_revocation(sig -> get_type())) { out << "revok"; } else if (sig -> get_type() == Signature_Type::SUBKEY_BINDING_SIGNATURE) { out << "sbind"; } else{ out << " sig "; } const std::array times = sig -> get_times(); // {signature creation time, signature expiration time, key expiration time} out << " " << hexlify(sig -> get_keyid()); // signature creation time (should always exist) if (times[0]) { out << " " << show_date(times[0]); } // else{ // out << " " << std::setfill(' ') << std::setw(10); // } // if the signature expires if (times[1]) { out << " " << show_date(times[1]); } else{ out << " " << std::setfill(' ') << std::setw(10); } // if the key expires if (times[2]) { out << " " << show_date(times[2]); } else{ out << " " << std::setfill(' ') << std::setw(10); } } else{} out << "\n"; } return out.str(); } //-------------------------------------------------------------------------------------------------------------- void Key::ExportUID(CPGPUserIdList &List) const { if (!meaningful()) { return; } for (Packet::Tag::Ptr const & p : packets) { if (p->get_tag() == Packet::USER_ID) { const auto& uid = std::static_pointer_cast (p)->get_contents(); List.Add(CPGPUserId()); auto& UserId = List.Last(); int Index = 0; bool Append; for (char ch : uid) { Append = false; switch (ch) { case '<': Index = 1; break; case '>': Index = 0; break; case '(': Index = 2; break; case ')': Index = 0; break; default: Append = true; break; } if (Append) { if (Index == 0) { UserId.Name.Append(ch); } else if (Index == 1) { UserId.Mail.Append(ch); } else { UserId.Desc.Append(ch); } } } UserId.Name = UserId.Name.TrimRight(); } } } //-------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- bool TryCleartextSignature(const CString &Key, const CString &Pass, const CString &Hash, const CString &ClearText, CString &SignText) { const std::string key(Key); const std::string pass(Pass); const std::string text(ClearText); const std::string hash(Hash.IsEmpty() ? "SHA256" : Hash); if (OpenPGP::Hash::NUMBER.find(hash) == OpenPGP::Hash::NUMBER.end()) { throw ExceptionFrm("PGP: Bad Hash Algorithm: %s.", hash.c_str()); } const OpenPGP::Sign::Args SignArgs(OpenPGP::SecretKey(key), pass,4, OpenPGP::Hash::NUMBER.at(hash)); const OpenPGP::CleartextSignature signature = OpenPGP::Sign::cleartext_signature(SignArgs, text); if (signature.meaningful()) { SignText << signature.write(); return true; } return false; } //-------------------------------------------------------------------------------------------------------------- void CleartextSignature(const CString &Key, const CString &Pass, const CString &Hash, const CString &ClearText, CString &SignText) { if (!TryCleartextSignature(Key, Pass, Hash, ClearText, SignText)) throw Delphi::Exception::Exception("PGP: Generated bad cleartext signature."); } //-------------------------------------------------------------------------------------------------------------- #ifdef USE_LIB_GCRYPT static int GInstanceCount = 0; pthread_mutex_t GPGPCriticalSection; CPGP *GPGP = nullptr; //-------------------------------------------------------------------------------------------------------------- //-- CPGPComponent --------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- inline void AddPGP() { if (GInstanceCount == 0) pthread_mutex_init(&GPGPCriticalSection, nullptr); pthread_mutex_lock(&GPGPCriticalSection); try { if (GInstanceCount == 0) { GPGP = CPGP::CreatePGP(); } GInstanceCount++; } catch (...) { } pthread_mutex_unlock(&GPGPCriticalSection); }; //-------------------------------------------------------------------------------------------------------------- inline void RemovePGP() { pthread_mutex_lock(&GPGPCriticalSection); try { GInstanceCount--; if (GInstanceCount == 0) { CPGP::DeletePGP(); GPGP = nullptr; } } catch (...) { } pthread_mutex_unlock(&GPGPCriticalSection); if (GInstanceCount == 0) pthread_mutex_destroy(&GPGPCriticalSection); }; //-------------------------------------------------------------------------------------------------------------- CPGPComponent::CPGPComponent() { AddPGP(); }; //-------------------------------------------------------------------------------------------------------------- CPGPComponent::~CPGPComponent() { RemovePGP(); }; //-------------------------------------------------------------------------------------------------------------- //-- CPGP ------------------------------------------------------------------------------------------------------ //-------------------------------------------------------------------------------------------------------------- CPGP::CPGP(): CObject() { m_LastError = GPG_ERR_NO_ERROR; m_OnVerbose = nullptr; if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) Initialize(); } //-------------------------------------------------------------------------------------------------------------- void CPGP::Initialize() { /* Version check should be the very first call because it makes sure that important subsystems are initialized. */ if (!gcry_check_version(GCRYPT_VERSION)) { throw EPGPError("Error: libgcrypt version mismatch"); } /* We don't want to see any warnings, e.g. because we have not yet parsed program options which might be used to suppress such warnings. */ //gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN); /* Allocate a pool of 16k secure memory. This makes the secure memory available and also drops privileges where needed. Note that by using functions like gcry_xmalloc_secure and gcry_mpi_snew Libgcrypt may expand the secure memory pool with memory which lacks the property of not being swapped out to disk. */ //gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); /* It is now okay to let Libgcrypt complain when there was/is a problem with the secure memory. */ //gcry_control(GCRYCTL_RESUME_SECMEM_WARN); /* Disable secure memory. */ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); /* No valuable keys are create, so we can speed up our RNG. */ gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); /* Tell Libgcrypt that initialization has completed. */ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } //-------------------------------------------------------------------------------------------------------------- bool CPGP::CheckForCipherError(gcry_error_t error) { int ignore[] = {0}; return CheckForCipherError(error, ignore, 0); } //-------------------------------------------------------------------------------------------------------------- bool CPGP::CheckForCipherError(gcry_error_t err, const int *ignore, int count) { if (err != GPG_ERR_NO_ERROR) { m_LastError = err; for (int i = 0; i < count; ++i) if (m_LastError == ignore[i]) return true; RaiseCipherError(m_LastError); } return false; } //-------------------------------------------------------------------------------------------------------------- void CPGP::RaiseCipherError(gcry_error_t err) { throw EPGPError("Error: %s/%s", gcry_strsource(err), gcry_strerror(err)); } //-------------------------------------------------------------------------------------------------------------- void CPGP::Verbose(LPCSTR AFormat, ...) { va_list args; va_start(args, AFormat); DoVerbose(AFormat, args); va_end(args); } //-------------------------------------------------------------------------------------------------------------- void CPGP::Verbose(LPCSTR AFormat, va_list args) { DoVerbose(AFormat, args); } //-------------------------------------------------------------------------------------------------------------- void CPGP::DoVerbose(LPCTSTR AFormat, va_list args) { if (m_OnVerbose != nullptr) { m_OnVerbose(this, AFormat, args); } } //-------------------------------------------------------------------------------------------------------------- //-- CPGPCipher ------------------------------------------------------------------------------------------------ //-------------------------------------------------------------------------------------------------------------- CPGPCipher::CPGPCipher(): CPGPComponent() { m_Handle = nullptr; } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Open(int algo, int mode, unsigned int flags) { return !GPGP->CheckForCipherError(gcry_cipher_open(&m_Handle, algo, mode, flags)); } //-------------------------------------------------------------------------------------------------------------- void CPGPCipher::Close() { if (m_Handle != nullptr) { gcry_cipher_close(m_Handle); } m_Handle = nullptr; } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::SetKey(const void *key, size_t keylen) { return !GPGP->CheckForCipherError(gcry_cipher_setkey(m_Handle, key, keylen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::SetIV(const void *iv, size_t ivlen) { return !GPGP->CheckForCipherError(gcry_cipher_setiv(m_Handle, iv, ivlen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::SetCTR(const void *ctr, size_t ctrlen) { return !GPGP->CheckForCipherError(gcry_cipher_setctr(m_Handle, ctr, ctrlen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Reset() { return !GPGP->CheckForCipherError(gcry_cipher_reset(m_Handle)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Authenticate(const void *abuf, size_t abuflen) { return !GPGP->CheckForCipherError(gcry_cipher_authenticate(m_Handle, abuf, abuflen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::GetTag(void *tag, size_t taglen) { return !GPGP->CheckForCipherError(gcry_cipher_gettag(m_Handle, tag, taglen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::CheckTag(gcry_cipher_hd_t h, const void *tag, size_t taglen) { return !GPGP->CheckForCipherError(gcry_cipher_checktag(m_Handle, tag, taglen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Encrypt(unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen) { return !GPGP->CheckForCipherError(gcry_cipher_encrypt(m_Handle, out, outsize, in, inlen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Decrypt(unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen) { return !GPGP->CheckForCipherError(gcry_cipher_decrypt(m_Handle, out, outsize, in, inlen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Final() { return !GPGP->CheckForCipherError(gcry_cipher_final(m_Handle)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Sync() { return !GPGP->CheckForCipherError(gcry_cipher_sync(m_Handle)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Ctl(int cmd, void *buffer, size_t buflen) { return !GPGP->CheckForCipherError(gcry_cipher_ctl(m_Handle, cmd, buffer, buflen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPCipher::Info(gcry_cipher_hd_t h, int what, void *buffer, size_t *nbytes) { return !GPGP->CheckForCipherError(gcry_cipher_info(m_Handle, what, buffer, nbytes)); } //-------------------------------------------------------------------------------------------------------------- //-- CPGPAlgo -------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- CPGPAlgo::CPGPAlgo(): CPGPComponent() { } //-------------------------------------------------------------------------------------------------------------- bool CPGPAlgo::Info(int algo, int what, void *buffer, size_t *nbytes) { return !GPGP->CheckForCipherError(gcry_cipher_algo_info(algo, what, buffer, nbytes)); } //-------------------------------------------------------------------------------------------------------------- size_t CPGPAlgo::KeyLen(int algo) { return !GPGP->CheckForCipherError(gcry_cipher_get_algo_keylen(algo)); } //-------------------------------------------------------------------------------------------------------------- size_t CPGPAlgo::BlkLen(int algo) { return !GPGP->CheckForCipherError(gcry_cipher_get_algo_blklen(algo)); } //-------------------------------------------------------------------------------------------------------------- const char *CPGPAlgo::Name(int algo) { return gcry_cipher_algo_name(algo); } //-------------------------------------------------------------------------------------------------------------- int CPGPAlgo::MapName(const char *name) { return gcry_cipher_map_name(name); } //-------------------------------------------------------------------------------------------------------------- int CPGPAlgo::ModeFromOid(const char *string) { return gcry_cipher_mode_from_oid(string); } //-------------------------------------------------------------------------------------------------------------- //-- CPGPMPI ---------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- CPGPMPI::CPGPMPI() { m_Handle = nullptr; } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::New(unsigned int nbits) { m_Handle = gcry_mpi_new(nbits); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::SNew(unsigned int nbits) { m_Handle = gcry_mpi_snew(nbits); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Copy(const gcry_mpi_t a) { m_Handle = gcry_mpi_copy(a); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Release() { gcry_mpi_release(m_Handle); } //-------------------------------------------------------------------------------------------------------------- gcry_mpi_t CPGPMPI::Set(const gcry_mpi_t u) { return gcry_mpi_set(m_Handle, u); } //-------------------------------------------------------------------------------------------------------------- gcry_mpi_t CPGPMPI::SetUI(unsigned long u) { return gcry_mpi_set_ui(m_Handle, u); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Swap(gcry_mpi_t b) { gcry_mpi_swap(m_Handle, b); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Snatch(const gcry_mpi_t u) { gcry_mpi_snatch(m_Handle, u); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Neg(gcry_mpi_t u) { gcry_mpi_neg(m_Handle, u); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Abs() { gcry_mpi_abs(m_Handle); } //-------------------------------------------------------------------------------------------------------------- int CPGPMPI::Cmp(const gcry_mpi_t v) const { return gcry_mpi_cmp(m_Handle, v); } //-------------------------------------------------------------------------------------------------------------- int CPGPMPI::CmpUI(unsigned long v) const { return gcry_mpi_cmp_ui(m_Handle, v); } //-------------------------------------------------------------------------------------------------------------- int CPGPMPI::IsNeg() const { return gcry_mpi_is_neg(m_Handle); } //-------------------------------------------------------------------------------------------------------------- bool CPGPMPI::Scan(enum gcry_mpi_format format, const unsigned char *buffer, size_t buflen, size_t *nscanned) { return !GPGP->CheckForCipherError(gcry_mpi_scan(&m_Handle, format, buffer, buflen, nscanned)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPMPI::Print(enum gcry_mpi_format format, unsigned char *buffer, size_t buflen, size_t *nwritten) const { return !GPGP->CheckForCipherError(gcry_mpi_print(format, buffer, buflen, nwritten, m_Handle)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPMPI::APrint(enum gcry_mpi_format format, unsigned char **buffer, size_t *nbytes) const { return !GPGP->CheckForCipherError(gcry_mpi_aprint(format, buffer, nbytes, m_Handle)); } //-------------------------------------------------------------------------------------------------------------- void CPGPMPI::Dump() { gcry_mpi_dump(m_Handle); } //-------------------------------------------------------------------------------------------------------------- //-- CPGPSexp -------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- CPGPSexp::CPGPSexp() { m_Handle = nullptr; } //-------------------------------------------------------------------------------------------------------------- CPGPSexp::~CPGPSexp() { Release(); } //-------------------------------------------------------------------------------------------------------------- bool CPGPSexp::New(const void *buffer, size_t length, int autodetect) { return !GPGP->CheckForCipherError(gcry_sexp_new(&m_Handle, buffer, length, autodetect)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPSexp::Create(void *buffer, size_t length, int autodetect, void (*freefnc)(void *)) { return !GPGP->CheckForCipherError(gcry_sexp_create(&m_Handle, buffer, length, autodetect, freefnc)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPSexp::Build(size_t *erroff, const char *format, ...) { bool result; va_list argList; va_start(argList, format); result = !GPGP->CheckForCipherError(gcry_sexp_build_array(&m_Handle, erroff, format, (void **) &argList)); va_end(argList); return result; } //-------------------------------------------------------------------------------------------------------------- bool CPGPSexp::Sscan(size_t *erroff, const char *buffer, size_t length) { return !GPGP->CheckForCipherError(gcry_sexp_sscan(&m_Handle, erroff, buffer, length)); } //-------------------------------------------------------------------------------------------------------------- size_t CPGPSexp::Sprint(int mode, char *buffer, size_t maxlength) { return gcry_sexp_sprint(m_Handle, mode, buffer, maxlength); } //-------------------------------------------------------------------------------------------------------------- void CPGPSexp::Release() { if (m_Handle != nullptr) gcry_sexp_release(m_Handle); m_Handle = nullptr; } //-------------------------------------------------------------------------------------------------------------- void CPGPSexp::Dump() { gcry_sexp_dump(m_Handle); } //-------------------------------------------------------------------------------------------------------------- size_t CPGPSexp::CanonLen(const unsigned char *buffer, size_t length, size_t *erroff, gcry_error_t *errcode) { return gcry_sexp_canon_len(buffer, length, erroff, errcode); } //-------------------------------------------------------------------------------------------------------------- gcry_sexp_t CPGPSexp::FindToken(const char *token, size_t toklen) { return gcry_sexp_find_token(m_Handle, token, toklen); } //-------------------------------------------------------------------------------------------------------------- int CPGPSexp::Length() { return gcry_sexp_length(m_Handle); } //-------------------------------------------------------------------------------------------------------------- gcry_sexp_t CPGPSexp::Nth(int number) { return gcry_sexp_nth(m_Handle, number); } //-------------------------------------------------------------------------------------------------------------- gcry_sexp_t CPGPSexp::Car() { return gcry_sexp_car(m_Handle); } //-------------------------------------------------------------------------------------------------------------- gcry_sexp_t CPGPSexp::Cdr() { return gcry_sexp_cdr(m_Handle); } //-------------------------------------------------------------------------------------------------------------- const char *CPGPSexp::NthData(int number, size_t *datalen) { return gcry_sexp_nth_data(m_Handle, number, datalen); } //-------------------------------------------------------------------------------------------------------------- void *CPGPSexp::NthBuffer(int number, size_t *rlength) { return gcry_sexp_nth_buffer(m_Handle, number, rlength); } //-------------------------------------------------------------------------------------------------------------- char *CPGPSexp::NthString(int number) { return gcry_sexp_nth_string(m_Handle, number); } //-------------------------------------------------------------------------------------------------------------- gcry_mpi_t CPGPSexp::NthMPI(int number, int mpifmt) { return gcry_sexp_nth_mpi(m_Handle, number, mpifmt); } //-------------------------------------------------------------------------------------------------------------- //-- CPGPKey --------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::Encrypt(gcry_sexp_t data, gcry_sexp_t pkey) { return !GPGP->CheckForCipherError(gcry_pk_encrypt(&m_Handle, data, pkey)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::Decrypt(gcry_sexp_t data, gcry_sexp_t skey) { return !GPGP->CheckForCipherError(gcry_pk_decrypt(&m_Handle, data, skey)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::Sign(gcry_sexp_t data, gcry_sexp_t skey) { return !GPGP->CheckForCipherError(gcry_pk_sign(&m_Handle, data, skey)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::Verify(gcry_sexp_t data, gcry_sexp_t pkey) { return !GPGP->CheckForCipherError(gcry_pk_verify(m_Handle, data, pkey)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::TestKey() { return !GPGP->CheckForCipherError(gcry_pk_testkey(m_Handle)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::AlgoInfo(int algo, int what, void *buffer, size_t *nbytes) { return !GPGP->CheckForCipherError(gcry_pk_algo_info(algo, what, buffer, nbytes)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::Ctl(int cmd, void *buffer, size_t buflen) { return !GPGP->CheckForCipherError(gcry_pk_ctl(cmd, buffer, buflen)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::GenKey(gcry_sexp_t parms) { return !GPGP->CheckForCipherError(gcry_pk_genkey(&m_Handle, parms)); } //-------------------------------------------------------------------------------------------------------------- bool CPGPKey::PubKeyGetSexp(int mode, gcry_ctx_t ctx) { return !GPGP->CheckForCipherError(gcry_pubkey_get_sexp(&m_Handle, mode, ctx)); } //-------------------------------------------------------------------------------------------------------------- const char *CPGPKey::AlgoName(int algo) { return gcry_pk_algo_name(algo); } //-------------------------------------------------------------------------------------------------------------- int CPGPKey::MapName(const char *name) { return gcry_pk_map_name(name); } //-------------------------------------------------------------------------------------------------------------- int CPGPKey::TestAlgo(int algo) { return gcry_pk_test_algo(algo); } //-------------------------------------------------------------------------------------------------------------- unsigned int CPGPKey::GetNBits() { return gcry_pk_get_nbits(m_Handle); } //-------------------------------------------------------------------------------------------------------------- unsigned char *CPGPKey::KeyGrip(unsigned char *array) { return gcry_pk_get_keygrip (m_Handle, array); } //-------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------- static void print_mpi(const char *text, const CPGPMPI& Mpi) { char *buf; void *bufaddr = &buf; try { Mpi.APrint(GCRYMPI_FMT_HEX, (unsigned char **) bufaddr, nullptr); } catch (...) { } if (GPGP->LastError()) { GPGP->Verbose("%s=[error printing number: %s]\n", text, gpg_strerror(GPGP->LastError())); } else { GPGP->Verbose("%s=0x%s\n", text, buf); gcry_free (buf); } } //-------------------------------------------------------------------------------------------------------------- static void check_generated_rsa_key(CPGPKey& Key, unsigned long expected_e) { CPGPKey Public(Key.FindToken("public-key", 0)); if (!Public.Handle()) throw EPGPError("public part missing in return value"); CPGPSexp List(Public.FindToken("e", 0)); CPGPMPI Mpi(List.NthMPI(1, 0)); if (!List.Handle() || !Mpi.Handle()) { throw EPGPError("public exponent not found"); } else if (!expected_e) { print_mpi("e", Mpi); } else if (Mpi.CmpUI(expected_e)) { print_mpi("e", Mpi); throw EPGPError("public exponent is not %lu", expected_e); } Mpi.Release(); List.Release(); Public.Release(); CPGPKey Secret(Key.FindToken("private-key", 0)); if (!Secret.Handle()) throw EPGPError("private part missing in return value"); Secret.TestKey(); Secret.Release(); } //-------------------------------------------------------------------------------------------------------------- void check_rsa_keys(COnPGPVerboseEvent && Verbose) { CPGPSexp KeyParm; CPGPKey Key; GPGP->OnVerbose(static_cast(Verbose)); /* Check that DSA generation works and that it can grok the qbits argument. */ GPGP->Verbose("Creating 5 1024 bit DSA keys"); for (int i = 0; i < 5; i++) { KeyParm.New("(genkey\n" " (dsa\n" " (nbits 4:1024)\n" " ))", 0, 1); Key.GenKey(KeyParm.Handle()); KeyParm.Release(); Key.Release(); GPGP->Verbose("Done"); } GPGP->Verbose("Creating 1536 bit DSA key"); KeyParm.New("(genkey\n" " (dsa\n" " (nbits 4:1536)\n" " (qbits 3:224)\n" " ))", 0, 1); Key.GenKey(KeyParm.Handle()); KeyParm.Release(); char buffer[20000]; Key.Sprint(GCRYSEXP_FMT_ADVANCED, buffer, sizeof buffer); GPGP->Verbose("=============================\n%s\n" "=============================\n", buffer); Key.Release(); GPGP->Verbose("Creating 1024 bit RSA key"); KeyParm.New("(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " ))", 0, 1); Key.GenKey(KeyParm.Handle()); KeyParm.Release(); check_generated_rsa_key (Key, 65537); Key.Release(); GPGP->Verbose("Creating 512 bit RSA key with e=257"); KeyParm.New("(genkey\n" " (rsa\n" " (nbits 3:512)\n" " (rsa-use-e 3:257)\n" " ))", 0, 1); Key.GenKey(KeyParm.Handle()); KeyParm.Release(); check_generated_rsa_key (Key, 257); Key.Release(); GPGP->Verbose("Creating 512 bit RSA key with default e"); KeyParm.New("(genkey\n" " (rsa\n" " (nbits 3:512)\n" " (rsa-use-e 1:0)\n" " ))", 0, 1); Key.GenKey(KeyParm.Handle()); KeyParm.Release(); check_generated_rsa_key (Key, 0); /* We don't expect a constant exponent. */ Key.Release(); } void get_aes_ctx(const char* passwd, CPGPCipher *Cipher) { const size_t keylen = 16; char passwd_hash[keylen]; size_t pass_len = strlen(passwd); Cipher->Open(GCRY_CIPHER_AES128,GCRY_CIPHER_MODE_CFB, 0); gcry_md_hash_buffer(GCRY_MD_MD5, (void*) &passwd_hash, (const void*) passwd, pass_len); Cipher->SetKey((const void *) &passwd_hash, keylen); Cipher->SetIV((const void *) &passwd_hash, keylen); } size_t get_keypair_size(int nbits) { size_t aes_blklen = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128); size_t keypair_nbits = 4 * (2 * nbits); size_t rem = keypair_nbits % aes_blklen; return (keypair_nbits + rem) / 8; } void load_key(const char *KeyFile, const char* Passwd, COnPGPVerboseEvent &&Verbose) { CString keyFile; keyFile.LoadFromFile(KeyFile); /* Grab a key pair password and create an AES context with it. */ CPGPCipher Cipher; get_aes_ctx("Aliens04", &Cipher); /* Read and decrypt the key pair from disk. */ size_t rsa_len = get_keypair_size(2048); void* rsa_buf = calloc(1, rsa_len); if (!rsa_buf) { throw Delphi::Exception::Exception("malloc: could not allocate rsa buffer"); } keyFile.Read(rsa_buf, rsa_len); Cipher.Decrypt((unsigned char*) rsa_buf, rsa_len, nullptr, 0); /* Load the key pair components into sexps. */ CPGPSexp KeyPair; KeyPair.New(rsa_buf, rsa_len, 0); free(rsa_buf); CPGPKey Public(KeyPair.FindToken("public-key", 0)); CPGPKey Secret(KeyPair.FindToken("private-key", 0)); /* Create a message. */ CPGPMPI Msg; CPGPSexp Data; const auto* s = (const unsigned char*) "Hello world."; Msg.Scan(GCRYMPI_FMT_USG, s, strlen((const char*) s), nullptr); Data.Build(nullptr,"(data (flags raw) (value %m))", Msg.Handle()); /* Encrypt the message. */ CPGPKey Ciph; Ciph.Encrypt(Data.Handle(), Public.Handle()); /* Decrypt the message. */ CPGPKey Plain; Plain.Decrypt(Ciph.Handle(), Secret.Handle()); /* Pretty-print the results. */ CPGPMPI outMsg(Plain.NthMPI(0, GCRYMPI_FMT_USG)); GPGP->Verbose("Original:"); Msg.Dump(); GPGP->Verbose("Decrypted:"); outMsg.Dump(); if (Msg.Cmp(outMsg.Handle())) { throw Delphi::Exception::Exception("Data corruption!"); } GPGP->Verbose("Messages match."); unsigned char obuf[64] = { 0 }; outMsg.Print(GCRYMPI_FMT_USG, (unsigned char*) &obuf, sizeof(obuf), nullptr); GPGP->Verbose("-> %s", (char *) obuf); } #endif } } }