/**
* @author Fra3zz
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge";
/**
* RSA Encrypt Private Key operation
*/
class RSAEncryptPrivate extends Operation {
/**
* RSAEncryptPrivate constructor
*/
constructor() {
super();
this.name = "RSA Encrypt Private Key";
this.module = "Ciphers";
this.description = "Encrypt a message with a PEM encoded RSA private key using the private key transform. Supports PKCS#1 and PKCS#8 key formats, including password-protected keys. The resulting ciphertext can be decrypted by anyone holding the corresponding public key.
Note: standard RSA encryption uses a public key. This operation applies the private key transform (equivalent to signing without hashing) and is sometimes required for compatibility with specific systems.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Private Key (PEM)",
type: "text",
value: "-----BEGIN RSA PRIVATE KEY-----"
},
{
name: "Key Password",
type: "text",
value: ""
},
{
name: "Encryption Scheme",
type: "option",
value: ["PKCS1 v1.5", "RAW"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [pemKey, password, scheme] = args;
if (!pemKey.startsWith("-----BEGIN")) {
throw new OperationError("Please enter a private key.");
}
let privKey;
try {
privKey = forge.pki.decryptRsaPrivateKey(pemKey, password);
} catch (err) {}
if (!privKey) {
try {
privKey = forge.pki.privateKeyFromPem(pemKey);
} catch (err) {
throw new OperationError(`Unable to load private key: ${err.message}`);
}
}
if (!privKey) {
throw new OperationError("Unable to load private key. Check the key format and password.");
}
try {
const plaintextBytes = forge.util.encodeUtf8(input);
const bt = scheme === "PKCS1 v1.5" ? 0x01 : false;
return forge.pki.rsa.encrypt(plaintextBytes, privKey, bt);
} catch (err) {
if (err.message && err.message.includes("too long")) {
throw new OperationError(`Message is too long for this key size.`);
}
throw new OperationError(err);
}
}
}
export default RSAEncryptPrivate;