mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-11 16:51:31 -04:00
Add and update PGP operations
Added: + PGP Sign cleartext + PGP Verify cleartext + PGP Add ASCII Armor + PGP Remove ASCII Armor + Many tests for all operations Updated: + PGP Encrypt (formatting of error messages) + PGP Decrypt (^^) + PGP Sign (this operation is now exclusively for non-clearsigned) + PGP Verify (^^)
This commit is contained in:
parent
3d661c953f
commit
f7b1e6e309
3 changed files with 789 additions and 29 deletions
|
@ -3179,4 +3179,140 @@ var OperationConfig = {
|
|||
},
|
||||
]
|
||||
},
|
||||
"PGP Sign": {
|
||||
description: "Input: An ASCII-Armored PGP private key (and optionally, the password needed to decrypt the private key); the public key of the recipient.<br><br>This operation uses PGP to produce an encrypted digital signature.<br><br>Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.<br><br>This function relies on OpenPGP.js for the implementation of PGP.<br><br>See more at https://openpgpjs.org/",
|
||||
run: PGP.runSign,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Public key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Private key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Private key password",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
]
|
||||
},
|
||||
"PGP Verify": {
|
||||
description: "Input: An ASCII-Armored PGP public key.<br><br>This operation uses PGP to decrypt and verify an encrypted digital signature.<br><br>Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.<br><br>This function relies on OpenPGP.js for the implementation of PGP.<br><br>See more at https://openpgpjs.org/",
|
||||
run: PGP.runVerify,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Public key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Private key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Private key password",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Display message in output",
|
||||
type: "boolean",
|
||||
value: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
"PGP Sign Cleartext": {
|
||||
description: "Input: An ASCII-Armored PGP private key (and optionally, the password needed to decrypt the private key).<br><br>This operation uses PGP to produce a digital signature.<br><br>Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.<br><br>This function relies on OpenPGP.js for the implementation of PGP.<br><br>See more at https://openpgpjs.org/",
|
||||
run: PGP.runSignCleartext,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Private key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Private key password",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
]
|
||||
},
|
||||
"PGP Verify Cleartext": {
|
||||
description: "Input: An ASCII-Armored PGP public key.<br><br>This operation uses PGP to verify a cleartext digital signature.<br><br>Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.<br><br>This function relies on OpenPGP.js for the implementation of PGP.<br><br>See more at https://openpgpjs.org/",
|
||||
run: PGP.runVerifyCleartext,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Public key",
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Display message in output",
|
||||
type: "boolean",
|
||||
value: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
"PGP Generate Key Pair": {
|
||||
description: "Input is ignored.<br><br>This operation generates a PGP key pair.<br><br>Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.<br><br>This function relies on OpenPGP.js for the implementation of PGP.<br><br>See more at https://openpgpjs.org/",
|
||||
run: PGP.runGenKeyPair,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Password",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Key size",
|
||||
type: "option",
|
||||
value: ["1024", "2048", "4096"],
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
]
|
||||
},
|
||||
"PGP Add ASCII Armor": {
|
||||
description: "",
|
||||
run: PGP.runAddArmor,
|
||||
inputType: "byteArray",
|
||||
outputType: "string",
|
||||
args: [
|
||||
{
|
||||
name: "Armor type",
|
||||
type: "option",
|
||||
value: PGP.ARMOR_TYPES,
|
||||
},
|
||||
],
|
||||
},
|
||||
"PGP Remove ASCII Armor": {
|
||||
description: "",
|
||||
run: PGP.runRemoveArmor,
|
||||
inputType: "string",
|
||||
outputType: "byteArray",
|
||||
args: [
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,6 +10,26 @@
|
|||
* @namespace
|
||||
*/
|
||||
var PGP = {
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ARMOR_TYPES: [
|
||||
"Message",
|
||||
"Public key",
|
||||
"Private key",
|
||||
],
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ARMOR_TYPE_MAPPING: {
|
||||
"Message": 3,
|
||||
"Public key": 4,
|
||||
"Private key": 5,
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
|
@ -24,20 +44,22 @@ var PGP = {
|
|||
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var options = {
|
||||
data: plaintext,
|
||||
publicKeys: openpgp.key.readArmored(publicKey).keys,
|
||||
};
|
||||
} catch (error) {
|
||||
reject("Failed to read public key", error);
|
||||
var publicKeys = openpgp.key.readArmored(publicKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Cannot read public key: " + err);
|
||||
}
|
||||
|
||||
var options = {
|
||||
data: plaintext,
|
||||
publicKeys: publicKeys,
|
||||
};
|
||||
|
||||
openpgp.encrypt(options)
|
||||
.then(function(ciphertext) {
|
||||
resolve(ciphertext.data);
|
||||
})
|
||||
.catch(function(error) {
|
||||
reject("Failed to encrypt input", error);
|
||||
.catch(function(err) {
|
||||
reject("Could not encrypt text: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -54,38 +76,336 @@ var PGP = {
|
|||
var privateKey = args[0],
|
||||
password = args[1];
|
||||
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
privateKey = openpgp.key.readArmored(privateKey).keys[0];
|
||||
} catch (error) {
|
||||
reject("Failed to read private key", error);
|
||||
} catch (err) {
|
||||
return reject("Cannot read private key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
if (password && password.length) {
|
||||
var message = openpgp.message.readArmored(input);
|
||||
} catch (err) {
|
||||
return reject("Cannot read message: " + err);
|
||||
}
|
||||
|
||||
var options = {
|
||||
message: message,
|
||||
privateKey: privateKey,
|
||||
};
|
||||
|
||||
try {
|
||||
if (password) {
|
||||
privateKey.decrypt(password);
|
||||
}
|
||||
} catch (error) {
|
||||
reject("Failed to decrypt private key", error);
|
||||
}
|
||||
|
||||
try {
|
||||
var options = {
|
||||
message: openpgp.message.readArmored(input),
|
||||
privateKey: privateKey,
|
||||
};
|
||||
} catch (error) {
|
||||
reject("Failed to read input message", error);
|
||||
} catch (err) {
|
||||
return reject("Cannot decrypt password: " + err);
|
||||
}
|
||||
|
||||
openpgp.decrypt(options)
|
||||
.then(function(plaintext) {
|
||||
resolve(plaintext.data);
|
||||
})
|
||||
.catch(function(error) {
|
||||
reject("Failed to encrypt input", error);
|
||||
.catch(function(err) {
|
||||
reject("Could not decrypt message: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Signs the input using PGP.
|
||||
*
|
||||
* @param {string} input - data to be signed
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSign: function (input, args) {
|
||||
var publicKey = args[0],
|
||||
privateKey = args[1],
|
||||
password = args[2];
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var publicKeys = openpgp.key.readArmored(publicKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Could not read public key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
var privateKeys = openpgp.key.readArmored(privateKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Could not read private key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
if (password) {
|
||||
privateKeys[0].decrypt(password);
|
||||
}
|
||||
} catch (err) {
|
||||
return reject("Cannot decrypt password: " + err);
|
||||
}
|
||||
|
||||
var options = {
|
||||
data: input,
|
||||
publicKeys: publicKeys,
|
||||
privateKeys: privateKeys,
|
||||
};
|
||||
|
||||
openpgp.encrypt(options)
|
||||
.then(function(signedData) {
|
||||
resolve(signedData.data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject("Could not sign input: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Verifies the signed input using PGP.
|
||||
*
|
||||
* @param {string} input - signed input to verify
|
||||
* @param {Object[]} args
|
||||
* @returns {string} - "true" or "false" depending on the validity of the signature
|
||||
*/
|
||||
runVerify: function (input, args) {
|
||||
var publicKey = args[0],
|
||||
privateKey = args[1],
|
||||
password = args[2],
|
||||
displayDecrypt = args[3];
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var publicKeys = openpgp.key.readArmored(publicKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Could not read public key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
var privateKeys = openpgp.key.readArmored(privateKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Could not read private key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
if (password) {
|
||||
privateKeys[0].decrypt(password);
|
||||
}
|
||||
} catch (err) {
|
||||
return reject("Cannot decrypt password: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
var message = openpgp.message.readArmored(input);
|
||||
} catch (err) {
|
||||
return reject("Could not read encrypted message: " + err);
|
||||
}
|
||||
|
||||
var verification = {
|
||||
verified: false,
|
||||
author: publicKeys[0].users[0].userId.userid,
|
||||
recipient: privateKeys[0].users[0].userId.userid,
|
||||
date: "",
|
||||
keyID: "",
|
||||
message: "",
|
||||
};
|
||||
|
||||
openpgp.decrypt({
|
||||
message: message,
|
||||
publicKeys: publicKeys,
|
||||
privateKey: privateKeys[0],
|
||||
})
|
||||
.then(function(decrypted) {
|
||||
if (decrypted.signatures) {
|
||||
// valid is either true or null, casting required.
|
||||
verification.verified = !!decrypted.signatures[0].valid;
|
||||
verification.keyID = decrypted.signatures[0].keyid.toHex();
|
||||
}
|
||||
|
||||
resolve([
|
||||
"Verified: " + verification.verified,
|
||||
"Key ID: " + verification.keyID,
|
||||
"Encrypted for: " + verification.recipient,
|
||||
"Signed on: " + verification.date,
|
||||
"Signed by: " + verification.author,
|
||||
"Signed with: ",
|
||||
"\n",
|
||||
displayDecrypt ? decrypted.data : "",
|
||||
].join("\n"));
|
||||
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject("Could not decrypt and verify message: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Clearsigns the input using PGP.
|
||||
*
|
||||
* @param {string} input - data to be signed
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSignCleartext: function (input, args) {
|
||||
var privateKey = args[0],
|
||||
password = args[1];
|
||||
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var privateKeys = openpgp.key.readArmored(privateKey).keys;
|
||||
|
||||
try {
|
||||
if (password) {
|
||||
privateKeys[0].decrypt(password);
|
||||
}
|
||||
} catch (err) {
|
||||
return reject("Cannot decrypt password: " + err);
|
||||
}
|
||||
|
||||
var options = {
|
||||
data: input,
|
||||
privateKeys: privateKeys,
|
||||
};
|
||||
|
||||
openpgp.sign(options)
|
||||
.then(function(signedData) {
|
||||
resolve(signedData.data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject("Could not clearsign input: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Verifies the clearsigned input using PGP.
|
||||
*
|
||||
* @param {string} input - signed input to verify
|
||||
* @param {Object[]} args
|
||||
* @returns {string} - "true" or "false" depending on the validity of the signature
|
||||
*/
|
||||
runVerifyCleartext: function (input, args) {
|
||||
var publicKey = args[0],
|
||||
displayDecrypt = args[1];
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
try {
|
||||
var publicKeys = openpgp.key.readArmored(publicKey).keys;
|
||||
} catch (err) {
|
||||
return reject("Could not read public key: " + err);
|
||||
}
|
||||
|
||||
try {
|
||||
var message = openpgp.cleartext.readArmored(input);
|
||||
} catch (err) {
|
||||
return reject("Could not read input message: " + err);
|
||||
}
|
||||
|
||||
var verification = {
|
||||
verified: false,
|
||||
author: publicKeys[0].users[0].userId.userid,
|
||||
date: "",
|
||||
keyID: "",
|
||||
message: message.text,
|
||||
};
|
||||
|
||||
openpgp.verify({
|
||||
message: message,
|
||||
publicKeys: publicKeys,
|
||||
})
|
||||
.then(function(verifiedData) {
|
||||
|
||||
if (verifiedData.signatures) {
|
||||
// valid is either true or null, casting required.
|
||||
verification.verified = !!verifiedData.signatures[0].valid;
|
||||
verification.keyID = verifiedData.signatures[0].keyid.toHex();
|
||||
}
|
||||
|
||||
resolve([
|
||||
"Verified: " + verification.verified,
|
||||
"Key ID: " + verification.keyID,
|
||||
"Signed on: " + verification.date,
|
||||
"Signed by: " + verification.author,
|
||||
"Signed with: ",
|
||||
"\n",
|
||||
displayDecrypt ? verification.message : "",
|
||||
].join("\n"));
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject("Could not verify message: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generates a PGP key pair.
|
||||
*
|
||||
* @param {string} input is ignored
|
||||
* @param {Object[]} args
|
||||
* @returns {string} - armored public key and private key separated by whitespace.
|
||||
*/
|
||||
runGenKeyPair: function (input, args) {
|
||||
var password = args[0],
|
||||
keySize = parseInt(args[1], 10),
|
||||
name = args[2],
|
||||
email = args[3];
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var options = {
|
||||
numBits: keySize,
|
||||
userIds: [{name: name, email: email}],
|
||||
};
|
||||
|
||||
if (password) {
|
||||
options.password = password;
|
||||
}
|
||||
|
||||
openpgp.generateKey(options)
|
||||
.then(function(key) {
|
||||
var output = [
|
||||
key.publicKeyArmored,
|
||||
key.privateKeyArmored,
|
||||
].join(""); // Preceding and trailing newlines are already generated.
|
||||
resolve(output);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject("Could not generate key pair: " + err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Turns raw PGP bytes into an ASCII armored string.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} - armored public key and private key separated by whitespace.
|
||||
*/
|
||||
runAddArmor: function (input, args) {
|
||||
var armorType = PGP.ARMOR_TYPE_MAPPING[args[0]];
|
||||
return openpgp.armor.encode(armorType, input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Turns an ASCII armored string into raw PGP bytes.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray} - armored public key and private key separated by whitespace.
|
||||
*/
|
||||
runRemoveArmor: function (input, args) {
|
||||
var decoded = openpgp.armor.decode(input);
|
||||
var uint8bytes = decoded.data;
|
||||
var bytes = Array.prototype.slice.call(uint8bytes);
|
||||
return bytes;
|
||||
},
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue