gchq/CyberChef · error · OperationError
Could not import private key: ${err}
Error message
Could not import private key: ${err} What it means
importPrivateKey wraps its entire body in try/catch and rethrows any failure as `Could not import private key: ${err}`. This catches: (a) kbpgp failing to parse the armored key (corrupt armor, bad base64, wrong format), (b) unlock_pgp failing because the passphrase is wrong, and (c) the inner 'Did not provide passphrase' OperationError being re-caught and rewrapped - so the no-passphrase message appears nested inside this one.
Source
Thrown at src/core/lib/PGP.mjs:96
try {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: privateKey,
opts: {
"no_check_keys": true
}
});
if (key.is_pgp_locked()) {
if (passphrase) {
await promisify(key.unlock_pgp.bind(key))({
passphrase
});
} else {
throw new OperationError("Did not provide passphrase with locked private key.");
}
}
return key;
} catch (err) {
throw new OperationError(`Could not import private key: ${err}`);
}
}
/**
* Import public key
*
* @param {string} publicKey
* @returns {Object}
*/
export async function importPublicKey (publicKey) {
try {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: publicKey,
opts: {
"no_check_keys": true
}
});
return key;View on GitHub (pinned to 4290ea7539)
Solutions
- Inspect the wrapped `err` in the caught exception - it distinguishes parse failure from wrong passphrase.
- Confirm the input is a valid OpenPGP ASCII-armored private key (BEGIN PGP PRIVATE KEY BLOCK).
- Verify the passphrase against the same key with gpg --list-packets or gpg --import.
- Trim stray whitespace/newlines from the armored text before importing.
- If using a locked key, ensure the passphrase is supplied (see error 107).
Example fix
// before
try {
const key = await PGP.importPrivateKey(maybeCorruptedArmor, pw);
} catch (e) {
console.error(e.message); // opaque wrapped message
}
// after - surface the underlying cause
try {
const key = await PGP.importPrivateKey(armor.trim(), pw);
} catch (e) {
const cause = e.message.replace(/^Could not import private key: /, '');
if (/passphrase/i.test(cause)) showUser('Wrong passphrase');
else if (/parse|armor|base64/i.test(cause)) showUser('Key is malformed');
} Defensive patterns
Strategy: try-catch
Validate before calling
function looksLikeArmoredPrivateKey(s) {
return /-----BEGIN PGP PRIVATE KEY BLOCK-----/.test(s) &&
/-----END PGP PRIVATE KEY BLOCK-----/.test(s);
}
if (!looksLikeArmoredPrivateKey(armor.trim())) {
throw new Error('Input is not an OpenPGP armored private key');
} Try / catch
try {
return await PGP.importPrivateKey(armor.trim(), passphrase);
} catch (e) {
const cause = String(e.message).replace(/^Could not import private key: /, '');
if (/passphrase/i.test(cause)) throw new Error('Wrong passphrase');
if (/parse|armor|base64|crc/i.test(cause)) throw new Error('Malformed private key armor');
throw new Error(cause);
} Prevention
- Trim whitespace/newlines from armored key text before importing.
- Inspect the wrapped cause string to differentiate parse vs passphrase errors.
- Confirm the block is OpenPGP (BEGIN PGP PRIVATE KEY BLOCK), not OpenSSL/SSH.
- Verify the passphrase with gpg --list-packets before importing.
When it happens
Trigger: Calling importPrivateKey with a malformed armored block; with a non-OpenPGP key (OpenSSL/SSH format); with the wrong passphrase; or omitting the passphrase on a locked key (the inner throw at line 91 is caught here).
Common situations: Wrong key format (PEM/OpenSSL vs OpenPGP armor); copy-paste stripped the armor headers or checksum; typo in the passphrase; key generated by a newer/older kbpgp version with incompatible packaging; trailing whitespace/newline corruption in the armored blob.
Related errors
- Could not import public key: ${err}
- Did not provide passphrase with locked private key.
- Enter the private key of the recipient.
- Couldn't decrypt message with provided private key: ${err}
- Enter the public key of the signer.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/b376e85681430d55.
Report an issue: GitHub.