gchq/CyberChef · error · OperationError
Did not provide passphrase with locked private key.
Error message
Did not provide passphrase with locked private key.
What it means
importPrivateKey detects that the supplied PGP secret key is passphrase-locked (key.is_pgp_locked() === true) but the caller did not pass a passphrase. Without unlocking, the key material is unusable for signing or decryption, so the import aborts with an explicit cause rather than a downstream obscure failure.
Source
Thrown at src/core/lib/PGP.mjs:91
* @param {string} privateKey
* @param {string} [passphrase]
* @returns {Object}
*/
export async function importPrivateKey(privateKey, passphrase) {
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,View on GitHub (pinned to 4290ea7539)
Solutions
- Provide the passphrase: importPrivateKey(privateKey, passphrase).
- Source the passphrase from a secure prompt or secret store rather than hardcoding.
- If you never want a passphrase, regenerate the key without one (kbpgp KeyManager.generate).
- Detect the locked state in your UI and surface a passphrase input before calling import.
Example fix
// before
const key = await PGP.importPrivateKey(armored); // locked key, no passphrase
// after
const key = await PGP.importPrivateKey(armored, passphrase);
// or prompt:
const passphrase = await promptUser('Private key passphrase');
const key = await PGP.importPrivateKey(armored, passphrase); Defensive patterns
Strategy: validation
Validate before calling
async function importPrivateKeySafe(armored, passphrase) {
// first import without unlocking to probe the locked state
const probe = await importKbpgpKey(armored);
if (probe.is_pgp_locked() && !passphrase) {
throw new Error('This key is locked; a passphrase is required.');
}
return PGP.importPrivateKey(armored, passphrase);
} Try / catch
try {
return await PGP.importPrivateKey(armored, passphrase);
} catch (e) {
if (/Did not provide passphrase/.test(e.message)) {
passphrase = await promptUser('Private key passphrase');
return PGP.importPrivateKey(armored, passphrase);
}
throw e;
} Prevention
- Always supply a passphrase argument when importing a locked key.
- Probe is_pgp_locked() up-front and surface a passphrase prompt in the UI.
- Store the passphrase in a secret manager rather than asking the user repeatedly.
- If you never intend to lock the key, generate it without a passphrase.
When it happens
Trigger: Calling importPrivateKey(armoredPrivateKey) or importPrivateKey(armoredPrivateKey, '') / undefined when the armored key was generated with a passphrase. Also if the passphrase argument is omitted entirely.
Common situations: User pastes a locked private key but leaves the passphrase field blank in the UI; passphrase stored in a separate secret manager that was not loaded; recipe/automation script hardcoded to skip the passphrase argument; key was just generated and locked by default.
Related errors
- Could not import private key: ${err}
- Could not import public key: ${err}
- 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/d897386c22b01938.
Report an issue: GitHub.