From d3fb18b3417a1c4397544fc070f0f19f0d04b9ea Mon Sep 17 00:00:00 2001
From: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com>
Date: Wed, 27 May 2026 19:25:55 +0000
Subject: [PATCH] Add PGP Sign (only) operation
---
src/core/config/Categories.json | 1 +
src/core/operations/PGPSign.mjs | 83 +++++++++++++++++++++++++++++++++
2 files changed, 84 insertions(+)
create mode 100644 src/core/operations/PGPSign.mjs
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 5fcba297..3404dc6d 100644
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -188,6 +188,7 @@
"Generate PGP Key Pair",
"PGP Encrypt",
"PGP Decrypt",
+ "PGP Sign",
"PGP Verify",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify",
diff --git a/src/core/operations/PGPSign.mjs b/src/core/operations/PGPSign.mjs
new file mode 100644
index 00000000..e3063d89
--- /dev/null
+++ b/src/core/operations/PGPSign.mjs
@@ -0,0 +1,83 @@
+/**
+ * @author GCHQDeveloper581
+ * @copyright Crown Copyright 2026
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import kbpgp from "kbpgp";
+import { ASP, importPrivateKey } from "../lib/PGP.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import * as es6promisify from "es6-promisify";
+const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
+
+/**
+ * PGP Sign operation
+ */
+class PGPSign extends Operation {
+
+ /**
+ * PGPSign constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "PGP Sign";
+ this.module = "PGP";
+ this.description = [
+ "Input: the message you want to sign",
+ "
",
+ "Arguments: the ASCII-armoured PGP private key of the sender.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function uses the Keybase implementation of PGP.",
+ ].join("\n");
+ this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc)
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Private key of signer",
+ "type": "text",
+ "value": ""
+ },
+ {
+ "name": "Private key passphrase (optional)",
+ "type": "string",
+ "value": ""
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ *
+ * @throws {OperationError} if failed private key import or failed encryption
+ */
+ async run(input, args) {
+ const message = input,
+ [privateKey, passphrase] = args;
+ let signedMessage;
+
+ if (!privateKey) throw new OperationError("Enter the private key of the signer.");
+ const privKey = await importPrivateKey(privateKey, passphrase);
+
+ try {
+ signedMessage = await promisify(kbpgp.box)({
+ "msg": message,
+ "sign_with": privKey,
+ "asp": ASP
+ });
+ } catch (err) {
+ throw new OperationError(`Couldn't sign message: ${err}`);
+ }
+
+ return signedMessage;
+ }
+
+}
+
+export default PGPSign;