Merge branch 'j433866-ssh-host-key'

This commit is contained in:
n1474335 2019-08-13 14:12:04 +01:00
commit 06b385563c
5 changed files with 220 additions and 2 deletions

View File

@ -122,7 +122,8 @@
"PGP Encrypt",
"PGP Decrypt",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify"
"PGP Decrypt and Verify",
"Parse SSH Host Key"
]
},
{
@ -166,6 +167,7 @@
"Parse IP range",
"Parse IPv6 address",
"Parse IPv4 header",
"Parse SSH Host Key",
"Parse URI",
"URL Encode",
"URL Decode",

View File

@ -0,0 +1,150 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Utils from "../Utils";
import { fromBase64 } from "../lib/Base64";
import { fromHex, toHexFast } from "../lib/Hex";
/**
* Parse SSH Host Key operation
*/
class ParseSSHHostKey extends Operation {
/**
* ParseSSHHostKey constructor
*/
constructor() {
super();
this.name = "Parse SSH Host Key";
this.module = "Default";
this.description = "Parses a SSH host key and extracts fields from it.<br>The key type can be:<ul><li>ssh-rsa</li><li>ssh-dss</li><li>ecdsa-sha2</li></ul>The key format can be either Hex or Base64.";
this.infoURL = "https://wikipedia.org/wiki/Secure_Shell";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Input Format",
type: "option",
value: [
"Auto",
"Base64",
"Hex"
]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [inputFormat] = args,
inputKey = this.convertKeyToBinary(input.trim(), inputFormat),
fields = this.parseKey(inputKey),
keyType = Utils.byteArrayToChars(fromHex(fields[0]), "");
let output = `Key type: ${keyType}`;
if (keyType === "ssh-rsa") {
output += `\nExponent: 0x${fields[1]}`;
output += `\nModulus: 0x${fields[2]}`;
} else if (keyType === "ssh-dss") {
output += `\np: 0x${fields[1]}`;
output += `\nq: 0x${fields[2]}`;
output += `\ng: 0x${fields[3]}`;
output += `\ny: 0x${fields[4]}`;
} else if (keyType.startsWith("ecdsa-sha2")) {
output += `\nCurve: ${Utils.byteArrayToChars(fromHex(fields[1]))}`;
output += `\nPoint: 0x${fields.slice(2)}`;
} else {
output += "\nUnsupported key type.";
output += `\nParameters: ${fields.slice(1)}`;
}
return output;
}
/**
* Converts the key to binary format from either hex or base64
*
* @param {string} inputKey
* @param {string} inputFormat
* @returns {byteArray}
*/
convertKeyToBinary(inputKey, inputFormat) {
const keyPattern = new RegExp(/^(?:[ssh]|[ecdsa-sha2])\S+\s+(\S*)/),
keyMatch = inputKey.match(keyPattern);
if (keyMatch) {
inputKey = keyMatch[1];
}
if (inputFormat === "Auto") {
inputFormat = this.detectKeyFormat(inputKey);
}
if (inputFormat === "Hex") {
return fromHex(inputKey);
} else if (inputFormat === "Base64") {
return fromBase64(inputKey, null, "byteArray");
} else {
throw new OperationError("Invalid input format.");
}
}
/**
* Detects if the key is base64 or hex encoded
*
* @param {string} inputKey
* @returns {string}
*/
detectKeyFormat(inputKey) {
const hexPattern = new RegExp(/^(?:[\dA-Fa-f]{2}[ ,;:]?)+$/);
const b64Pattern = new RegExp(/^\s*(?:[A-Za-z\d+/]{4})+(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?\s*$/);
if (hexPattern.test(inputKey)) {
return "Hex";
} else if (b64Pattern.test(inputKey)) {
return "Base64";
} else {
throw new OperationError("Unable to detect input key format.");
}
}
/**
* Parses fields from the key
*
* @param {byteArray} key
*/
parseKey(key) {
const fields = [];
while (key.length > 0) {
const lengthField = key.slice(0, 4);
let decodedLength = 0;
for (let i = 0; i < lengthField.length; i++) {
decodedLength += lengthField[i];
decodedLength = decodedLength << 8;
}
decodedLength = decodedLength >> 8;
// Break if length wasn't decoded correctly
if (decodedLength <= 0) break;
fields.push(toHexFast(key.slice(4, 4 + decodedLength)));
key = key.slice(4 + decodedLength);
}
return fields;
}
}
export default ParseSSHHostKey;

View File

@ -136,7 +136,7 @@ TestRegister.addApiTests([
it("chef.help: returns multiple results", () => {
const result = chef.help("base 64");
assert.strictEqual(result.length, 10);
assert.strictEqual(result.length, 11);
}),
it("chef.help: looks in description for matches too", () => {

View File

@ -86,6 +86,7 @@ import "./tests/Typex";
import "./tests/BLAKE2b";
import "./tests/BLAKE2s";
import "./tests/Protobuf";
import "./tests/ParseSSHHostKey";
// Cannot test operations that use the File type yet
//import "./tests/SplitColourChannels";

View File

@ -0,0 +1,65 @@
/**
* Parse SSH Host Key tests
*
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "SSH Host Key: RSA",
input: "AAAAB3NzaC1yc2EAAAADAQABAAABAQDiJZ/9W9Ix/Dk9b+K4E+RGCug1AtkGXaJ9vNIY0YHFHLpWsB8DAuh/cGEI9TLbL1gzR2wG+RJNQ2EAQVWe6ypkK63Jm4zw4re+vhEiszpnP889J0h5N9yzyTndesrl4d3cQtv861FcKDPxUJbRALdtl6gwOB7BCL8gsXJLLVLO4EesrbPXD454qpVt7CgJXEXByOFjcIm3XwkdOnXMPHHnMSD7EIN1SvQMD6PfIDrbDd6KQt5QXW/Rc/BsfX5cbUIV1QW5A/GbepXHHKmWRtLC2J/mH3hW2Zq/hITPEaJdG1CtIilQmJaZGXpfGIwFeb0Av9pSL926arZZ6vDi9ctF",
expectedOutput: `Key type: ssh-rsa
Exponent: 0x010001
Modulus: 0x00e2259ffd5bd231fc393d6fe2b813e4460ae83502d9065da27dbcd218d181c51cba56b01f0302e87f706108f532db2f5833476c06f9124d43610041559eeb2a642badc99b8cf0e2b7bebe1122b33a673fcf3d27487937dcb3c939dd7acae5e1dddc42dbfceb515c2833f15096d100b76d97a830381ec108bf20b1724b2d52cee047acadb3d70f8e78aa956dec28095c45c1c8e1637089b75f091d3a75cc3c71e73120fb1083754af40c0fa3df203adb0dde8a42de505d6fd173f06c7d7e5c6d4215d505b903f19b7a95c71ca99646d2c2d89fe61f7856d99abf8484cf11a25d1b50ad222950989699197a5f188c0579bd00bfda522fddba6ab659eaf0e2f5cb45`,
recipeConfig: [
{
op: "Parse SSH Host Key",
args: ["Base64"]
}
]
},
{
name: "SSH Host Key: DSA",
input: "AAAAB3NzaC1kc3MAAACBAMnoZCOzvaQqs//9mxK2USZvJBc7b1dFJiBcV80abN6maE+203pTRPIPCpPt0deQxv4YN3dSHoodEcArWxs1QRAIuRsQIvsUP7chovzGnxP84XWK5sbfrseD0vxZ7UR0NaAFPcSgeXcWC1SG9uvrAJQlyp4DBy+fKuqiYmwaz0bHAAAAFQCXNJ4yiE1V7LpCU2V1JKbqDvICMwAAAIB/5aR1iBOeyCVpj0dP3YZmoxd9R7FCC/0UuOf0lx4E6WHT6Z2QuPBhc2mpNDq2M0VF9oJfVWgcfG8r1rlXaCYODSacGcbnW5VKQ+LKkkALmg4h8jFCHReUC+Hmia/v8LyDwPO1wK6ETn7a3m80yM7gAU5ZNurVIVVP2lB65mjEsQAAAIA3ct9YRB6iUCvOD45sZM1C9oTC24Ttmaou0GcpWx3h0/iZ8mbil1cjaO9frRNZ/vSSVWEhEDNG8gwkjZWlvnJL3y1XUxbMll4WbmI/Q1kzKwopceaFwMbYTPKDg6L1RtCMUxSUyKsFk1c4SpEPlDS7DApZs5PgmWgMd/u6vwMXyg==",
expectedOutput: `Key type: ssh-dss
p: 0x00c9e86423b3bda42ab3fffd9b12b651266f24173b6f574526205c57cd1a6cdea6684fb6d37a5344f20f0a93edd1d790c6fe183777521e8a1d11c02b5b1b35411008b91b1022fb143fb721a2fcc69f13fce1758ae6c6dfaec783d2fc59ed447435a0053dc4a07977160b5486f6ebeb009425ca9e03072f9f2aeaa2626c1acf46c7
q: 0x0097349e32884d55ecba4253657524a6ea0ef20233
g: 0x7fe5a47588139ec825698f474fdd8666a3177d47b1420bfd14b8e7f4971e04e961d3e99d90b8f0617369a9343ab6334545f6825f55681c7c6f2bd6b95768260e0d269c19c6e75b954a43e2ca92400b9a0e21f231421d17940be1e689afeff0bc83c0f3b5c0ae844e7edade6f34c8cee0014e5936ead521554fda507ae668c4b1
y: 0x3772df58441ea2502bce0f8e6c64cd42f684c2db84ed99aa2ed067295b1de1d3f899f266e297572368ef5fad1359fef492556121103346f20c248d95a5be724bdf2d575316cc965e166e623f4359332b0a2971e685c0c6d84cf28383a2f546d08c531494c8ab059357384a910f9434bb0c0a59b393e099680c77fbbabf0317ca`,
recipeConfig: [
{
op: "Parse SSH Host Key",
args: ["Base64"]
}
]
},
{
name: "SSH Host Key: ECDSA",
input: "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGxZWSAGJyJQoVBwFCpr420eRUZDE/kw2YWm5vDro8050DZ1ZzqIuYaNl0BGzMcRTeasGtJuI8G84ZQQSgca3C4=",
expectedOutput: `Key type: ecdsa-sha2-nistp256
Curve: nistp256
Point: 0x046c59592006272250a15070142a6be36d1e45464313f930d985a6e6f0eba3cd39d03675673a88b9868d974046ccc7114de6ac1ad26e23c1bce194104a071adc2e`,
recipeConfig: [
{
op: "Parse SSH Host Key",
args: ["Base64"]
}
]
},
{
name: "SSH Host Key: Extract key",
input: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDiJZ/9W9Ix/Dk9b+K4E+RGCug1AtkGXaJ9vNIY0YHFHLpWsB8DAuh/cGEI9TLbL1gzR2wG+RJNQ2EAQVWe6ypkK63Jm4zw4re+vhEiszpnP889J0h5N9yzyTndesrl4d3cQtv861FcKDPxUJbRALdtl6gwOB7BCL8gsXJLLVLO4EesrbPXD454qpVt7CgJXEXByOFjcIm3XwkdOnXMPHHnMSD7EIN1SvQMD6PfIDrbDd6KQt5QXW/Rc/BsfX5cbUIV1QW5A/GbepXHHKmWRtLC2J/mH3hW2Zq/hITPEaJdG1CtIilQmJaZGXpfGIwFeb0Av9pSL926arZZ6vDi9ctF test@test",
expectedOutput: `Key type: ssh-rsa
Exponent: 0x010001
Modulus: 0x00e2259ffd5bd231fc393d6fe2b813e4460ae83502d9065da27dbcd218d181c51cba56b01f0302e87f706108f532db2f5833476c06f9124d43610041559eeb2a642badc99b8cf0e2b7bebe1122b33a673fcf3d27487937dcb3c939dd7acae5e1dddc42dbfceb515c2833f15096d100b76d97a830381ec108bf20b1724b2d52cee047acadb3d70f8e78aa956dec28095c45c1c8e1637089b75f091d3a75cc3c71e73120fb1083754af40c0fa3df203adb0dde8a42de505d6fd173f06c7d7e5c6d4215d505b903f19b7a95c71ca99646d2c2d89fe61f7856d99abf8484cf11a25d1b50ad222950989699197a5f188c0579bd00bfda522fddba6ab659eaf0e2f5cb45`,
recipeConfig: [
{
op: "Parse SSH Host Key",
args: ["Base64"]
}
]
}
]);