QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
RnpCrypto Class Reference

OpenPGP encryption and decryption in-process, through RNP. More...

#include <rnpcrypto.h>

Classes

struct  KeyInfo
 One primary key in the keyring, as the Users dialog lists keys. More...

Public Types

using PassphraseProvider = std::function<QString(const QString &keyId)>
 Asks for the passphrase of a secret key.

Public Member Functions

 RnpCrypto ()
 Creates an empty keyring.
 ~RnpCrypto ()
 Frees the keyring and everything RNP holds for it.
 RnpCrypto (const RnpCrypto &)=delete
auto operator= (const RnpCrypto &) -> RnpCrypto &=delete
 RnpCrypto (RnpCrypto &&)=delete
auto operator= (RnpCrypto &&) -> RnpCrypto &=delete
auto isValid () const -> bool
 Whether the RNP context could be created at all.
auto importKeys (const QByteArray &keyData, QString *error=nullptr) -> QStringList
 Imports public and secret keys from armored or binary key data.
void setPassphraseProvider (PassphraseProvider provider)
 Sets how secret-key passphrases are obtained.
void setMaxPlaintextBytes (qint64 bytes)
 Sets the most bytes of plaintext decrypt() may produce.
auto encrypt (const QByteArray &plaintext, const QStringList &recipients, QString *error=nullptr) -> QByteArray
 Encrypts plaintext to every recipient, as one message.
auto decrypt (const QByteArray &ciphertext, QString *error=nullptr, bool *ok=nullptr) -> QByteArray
 Decrypts an OpenPGP message with any secret key in the keyring.
auto listKeys (bool secretOnly=false) const -> QList< KeyInfo >
 The primary keys in the keyring.
auto sign (const QByteArray &data, const QString &signer, QString *error=nullptr) -> QByteArray
 Makes a detached signature over data, as gpg –detach-sign –local-user signer does (for .gpg-id.sig).
auto verify (const QByteArray &data, const QByteArray &signature, QString *error=nullptr) -> QStringList
 Checks a detached signature over data, as QtPass reads gpg's VALIDSIG.
auto protectKey (const QString &fingerprint, const QString &passphrase, QString *error=nullptr) -> bool
 Protects the secret parts of a key with passphrase.
auto saveKeyring (const QString &dir, bool allowUnprotected=false, QString *error=nullptr) const -> bool
 Writes the keyring to dir: keyring.gpg, public and secret keys in one file (OpenPGP keys, as GnuPG 1 kept them), owner-only and replaced whole, so a reader sees the old keyring or the new one.
auto loadKeyring (const QString &dir, QString *error=nullptr) -> bool
 Adds the keyring in dir (as saveKeyring() wrote it) to this one. Secret keys stay protected until an operation needs them.

Static Public Attributes

static constexpr qint64 kMaxPlaintextBytes = 64LL * 1024 * 1024
 Most bytes of plaintext decrypt() produces by default.
static constexpr qint64 kMaxKeyringBytes = 64LL * 1024 * 1024
 Most bytes of a keyring file: saveKeyring() writes no larger one, loadKeyring() reads no larger one.

Private Attributes

rnp_ffi_st * m_ffi = nullptr
 RNP's handle holding this object's keyring; null when RNP could not be initialised, and every operation then fails with an error.
PassphraseProvider m_passphrase
 Asked for the passphrase of a locked secret key during decryption; set with setPassphraseProvider(), empty for none.
qint64 m_maxPlaintext = kMaxPlaintextBytes
 Largest plaintext decrypt() returns, in bytes.

Detailed Description

OpenPGP encryption and decryption in-process, through RNP.

A spike towards a backend that needs no gpg, git or pass binary (#2005): the same work ImitatePass hands to gpg, done by the RNP library (the OpenPGP code Thunderbird uses). Keys live in this object's own keyring, filled from armored exports (gpg –export / –export-secret-keys); it never reads or writes ~/.gnupg. Built only with CONFIG+=rnp.

Output is binary OpenPGP, as pass and QtPass write .gpg files. Every call reports failure through its return value and a human-readable error.

Security trade-off (SECURITY.md, "In-process OpenPGP"): with gpg, QtPass never holds a secret key; gpg-agent does, or a smartcard. Here the secret key is imported into this process and, while a message is decrypted, the unlocked key and the passphrase are in its memory. Imported keys keep their own passphrase protection; no smartcard support. A mode built on this must be chosen deliberately, never used as a silent fallback for a missing gpg.

Definition at line 41 of file rnpcrypto.h.

Member Typedef Documentation

◆ PassphraseProvider

using RnpCrypto::PassphraseProvider = std::function<QString(const QString &keyId)>

Asks for the passphrase of a secret key.

Called with the key's 16-hex-digit key ID; return an empty string to give up.

Definition at line 86 of file rnpcrypto.h.

Constructor & Destructor Documentation

◆ RnpCrypto()

RnpCrypto::RnpCrypto ( )

Creates an empty keyring.

Definition at line 504 of file rnpcrypto.cpp.

◆ ~RnpCrypto()

RnpCrypto::~RnpCrypto ( )

Frees the keyring and everything RNP holds for it.

Definition at line 512 of file rnpcrypto.cpp.

Member Function Documentation

◆ decrypt()

auto RnpCrypto::decrypt ( const QByteArray & ciphertext,
QString * error = nullptr,
bool * ok = nullptr ) -> QByteArray

Decrypts an OpenPGP message with any secret key in the keyring.

Only an integrity-protected message is accepted (SEIPD with MDC, or AEAD such as the OCB packets GnuPG 2.4 writes): one without (CFB with no MDC, the EFAIL kind) is refused, as GnuPG has since 2.2.8. A plaintext over the limit (setMaxPlaintextBytes()) fails too.

Parameters
ciphertextBinary or armored OpenPGP message.
errorSet to the reason when decryption fails.
okSet to whether decryption succeeded, since an entry can be empty.
Returns
The plaintext, empty on failure.

Definition at line 640 of file rnpcrypto.cpp.

◆ encrypt()

auto RnpCrypto::encrypt ( const QByteArray & plaintext,
const QStringList & recipients,
QString * error = nullptr ) -> QByteArray

Encrypts plaintext to every recipient, as one message.

Parameters
plaintextThe entry's content.
recipientsAs a .gpg-id lists them, in the forms gpg -r takes: a fingerprint (40 or 64 hex digits, blanks allowed), a long or short (8 hex digits) key ID with or without 0x, an e-mail address (the key with a user ID of that address, any case; stricter than gpg's substring search; a user ID with no address in angle brackets must then be just the address, so "alice@example.org (work)" is not found by its address), or a whole user ID or part of one. Revoked user IDs, and ones without a valid self-signature, name nothing. Each must name exactly one key that can encrypt (not expired or revoked, with a usable encryption key); an empty recipient is an error.
errorSet to the reason when encryption fails, naming the first recipient that has no usable key or names more than one.
Returns
The binary OpenPGP message, empty on failure.

Definition at line 586 of file rnpcrypto.cpp.

◆ importKeys()

auto RnpCrypto::importKeys ( const QByteArray & keyData,
QString * error = nullptr ) -> QStringList

Imports public and secret keys from armored or binary key data.

Parameters
keyDataOutput of gpg –export or –export-secret-keys.
errorSet to the reason when the import fails.
Returns
The primary key fingerprints imported, empty on failure.

Definition at line 535 of file rnpcrypto.cpp.

◆ isValid()

auto RnpCrypto::isValid ( ) const -> bool
nodiscard

Whether the RNP context could be created at all.

Returns
False only when RNP itself failed to initialise.

Definition at line 518 of file rnpcrypto.cpp.

◆ listKeys()

auto RnpCrypto::listKeys ( bool secretOnly = false) const -> QList< KeyInfo >
nodiscard

The primary keys in the keyring.

Parameters
secretOnlyOnly keys with a secret part here.
Returns
One entry per primary key, in the keyring's order.

Definition at line 785 of file rnpcrypto.cpp.

Here is the caller graph for this function:

◆ loadKeyring()

auto RnpCrypto::loadKeyring ( const QString & dir,
QString * error = nullptr ) -> bool

Adds the keyring in dir (as saveKeyring() wrote it) to this one. Secret keys stay protected until an operation needs them.

keyring.gpg is read as a regular file, not through a link (nor is dir itself a link or junction; its parents are as configured), and only up to kMaxKeyringBytes. A missing or empty file is an empty keyring, not an error.

Parameters
dirThe keyring folder.
errorSet to the reason when loading fails.
Returns
Whether the keyring loaded (or there was none).

Definition at line 1100 of file rnpcrypto.cpp.

Here is the call graph for this function:

◆ protectKey()

auto RnpCrypto::protectKey ( const QString & fingerprint,
const QString & passphrase,
QString * error = nullptr ) -> bool

Protects the secret parts of a key with passphrase.

For a key imported without protection: saveKeyring() keeps secret keys on disk only protected by their own passphrase. Only the parts not yet protected get passphrase, so a key left half protected can be finished; the others keep theirs (no passphrase is changed here). A key all of whose secret parts are protected already is an error. The UTF-8 copy made here is wiped afterwards; passphrase itself, and any copy the caller holds, is the caller's to wipe.

Parameters
fingerprintThe primary key's fingerprint.
passphraseThe passphrase; not empty.
errorSet to the reason when not every part ended up protected.
Returns
Whether every secret part of the key here is now protected.

Definition at line 950 of file rnpcrypto.cpp.

◆ saveKeyring()

auto RnpCrypto::saveKeyring ( const QString & dir,
bool allowUnprotected = false,
QString * error = nullptr ) const -> bool

Writes the keyring to dir: keyring.gpg, public and secret keys in one file (OpenPGP keys, as GnuPG 1 kept them), owner-only and replaced whole, so a reader sees the old keyring or the new one.

The file holds exactly this keyring afterwards: load the folder first (loadKeyring()), or every key on disk that is not in this keyring is gone. That is how a removed key disappears from disk.

Secret keys are written as they are held: protected by their own passphrase, never decrypted for this. A secret key without protection is refused (nothing is written) unless allowUnprotected, the user's explicit consent; protectKey() first is the other way. So is a secret part whose protection RNP cannot name.

Parameters
dirThe keyring folder, created owner-only if missing (on Windows: as private as the user profile it is in); QtPass's own, never ~/.gnupg, and not a link or junction (the folder itself; its parents are as configured).
allowUnprotectedWrite unprotected secret keys as well.
errorSet to the reason when nothing was written, naming the first unprotected key.
Returns
Whether the keyring was written; false, and nothing written, also when it would be larger than loadKeyring() reads.

Definition at line 1009 of file rnpcrypto.cpp.

Here is the call graph for this function:

◆ setMaxPlaintextBytes()

void RnpCrypto::setMaxPlaintextBytes ( qint64 bytes)

Sets the most bytes of plaintext decrypt() may produce.

Parameters
bytesThe limit; kMaxPlaintextBytes until set. A value that is not positive is ignored and the limit stays as it was: there is no "unlimited". A value above 4 GiB - 1 is capped to 4 GiB - 1, as RNP keeps the limit in 32 bits.

Definition at line 520 of file rnpcrypto.cpp.

◆ setPassphraseProvider()

void RnpCrypto::setPassphraseProvider ( PassphraseProvider provider)

Sets how secret-key passphrases are obtained.

Parameters
providerCalled when decryption needs a locked key.

Definition at line 531 of file rnpcrypto.cpp.

◆ sign()

auto RnpCrypto::sign ( const QByteArray & data,
const QString & signer,
QString * error = nullptr ) -> QByteArray

Makes a detached signature over data, as gpg –detach-sign –local-user signer does (for .gpg-id.sig).

Parameters
dataThe bytes signed, a .gpg-id as written.
signerThe key: a fingerprint or key ID names exactly that key; an e-mail address the key with a user ID of that address (any case); else a user ID, whole or in part. It must name exactly one key that can sign and whose secret key is here; that key is used, not another.
errorSet to the reason when signing fails.
Returns
The binary signature, empty on failure.

Definition at line 845 of file rnpcrypto.cpp.

◆ verify()

auto RnpCrypto::verify ( const QByteArray & data,
const QByteArray & signature,
QString * error = nullptr ) -> QStringList

Checks a detached signature over data, as QtPass reads gpg's VALIDSIG.

The first signature that verifies decides. A signature by a key that is now revoked (or whose primary is) counts for nothing, as with GnuPG in GpgIdSigner; one by a key that has since expired still counts, as gpg calls it a good signature.

Parameters
dataThe signed bytes.
signatureBinary or armored detached signature.
errorSet to the reason when no signature counts.
Returns
The signing key's fingerprint and its primary key's, as GpgIdSigner::validSigFingerprints() gives them; empty when no signature counts.

Definition at line 897 of file rnpcrypto.cpp.

Member Data Documentation

◆ kMaxKeyringBytes

qint64 RnpCrypto::kMaxKeyringBytes = 64LL * 1024 * 1024
staticconstexpr

Most bytes of a keyring file: saveKeyring() writes no larger one, loadKeyring() reads no larger one.

Far beyond a keyring of a few hundred keys; a file larger than this is not read at all.

Definition at line 104 of file rnpcrypto.h.

◆ kMaxPlaintextBytes

qint64 RnpCrypto::kMaxPlaintextBytes = 64LL * 1024 * 1024
staticconstexpr

Most bytes of plaintext decrypt() produces by default.

An OpenPGP message is compressed, so a small entry in a shared store can decompress to gigabytes; decrypt() fails at this many instead of filling memory. The same limit QtPass gives gpg (–max-output).

Definition at line 95 of file rnpcrypto.h.

◆ m_ffi

rnp_ffi_st* RnpCrypto::m_ffi = nullptr
private

RNP's handle holding this object's keyring; null when RNP could not be initialised, and every operation then fails with an error.

Definition at line 290 of file rnpcrypto.h.

◆ m_maxPlaintext

qint64 RnpCrypto::m_maxPlaintext = kMaxPlaintextBytes
private

Largest plaintext decrypt() returns, in bytes.

Definition at line 297 of file rnpcrypto.h.

◆ m_passphrase

PassphraseProvider RnpCrypto::m_passphrase
private

Asked for the passphrase of a locked secret key during decryption; set with setPassphraseProvider(), empty for none.

Definition at line 295 of file rnpcrypto.h.


The documentation for this class was generated from the following files: