ParseSSHHostKey.mjs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /**
  2. * @author j433866 [j433866@gmail.com]
  3. * @copyright Crown Copyright 2019
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. import OperationError from "../errors/OperationError";
  8. import Utils from "../Utils";
  9. import { fromBase64 } from "../lib/Base64";
  10. import { fromHex, toHexFast } from "../lib/Hex";
  11. /**
  12. * Parse SSH Host Key operation
  13. */
  14. class ParseSSHHostKey extends Operation {
  15. /**
  16. * ParseSSHHostKey constructor
  17. */
  18. constructor() {
  19. super();
  20. this.name = "Parse SSH Host Key";
  21. this.module = "Default";
  22. 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.";
  23. this.infoURL = "https://wikipedia.org/wiki/Secure_Shell";
  24. this.inputType = "string";
  25. this.outputType = "string";
  26. this.args = [
  27. {
  28. name: "Input Format",
  29. type: "option",
  30. value: [
  31. "Auto",
  32. "Base64",
  33. "Hex"
  34. ]
  35. }
  36. ];
  37. }
  38. /**
  39. * @param {string} input
  40. * @param {Object[]} args
  41. * @returns {string}
  42. */
  43. run(input, args) {
  44. const [inputFormat] = args,
  45. inputKey = this.convertKeyToBinary(input.trim(), inputFormat),
  46. fields = this.parseKey(inputKey),
  47. keyType = Utils.byteArrayToChars(fromHex(fields[0]), "");
  48. let output = `Key type: ${keyType}`;
  49. if (keyType === "ssh-rsa") {
  50. output += `\nExponent: 0x${fields[1]}`;
  51. output += `\nModulus: 0x${fields[2]}`;
  52. } else if (keyType === "ssh-dss") {
  53. output += `\np: 0x${fields[1]}`;
  54. output += `\nq: 0x${fields[2]}`;
  55. output += `\ng: 0x${fields[3]}`;
  56. output += `\ny: 0x${fields[4]}`;
  57. } else if (keyType.startsWith("ecdsa-sha2")) {
  58. output += `\nCurve: ${Utils.byteArrayToChars(fromHex(fields[1]))}`;
  59. output += `\nPoint: 0x${fields.slice(2)}`;
  60. } else {
  61. output += "\nUnsupported key type.";
  62. output += `\nParameters: ${fields.slice(1)}`;
  63. }
  64. return output;
  65. }
  66. /**
  67. * Converts the key to binary format from either hex or base64
  68. *
  69. * @param {string} inputKey
  70. * @param {string} inputFormat
  71. * @returns {byteArray}
  72. */
  73. convertKeyToBinary(inputKey, inputFormat) {
  74. const keyPattern = new RegExp(/^(?:[ssh]|[ecdsa-sha2])\S+\s+(\S*)/),
  75. keyMatch = inputKey.match(keyPattern);
  76. if (keyMatch) {
  77. inputKey = keyMatch[1];
  78. }
  79. if (inputFormat === "Auto") {
  80. inputFormat = this.detectKeyFormat(inputKey);
  81. }
  82. if (inputFormat === "Hex") {
  83. return fromHex(inputKey);
  84. } else if (inputFormat === "Base64") {
  85. return fromBase64(inputKey, null, "byteArray");
  86. } else {
  87. throw new OperationError("Invalid input format.");
  88. }
  89. }
  90. /**
  91. * Detects if the key is base64 or hex encoded
  92. *
  93. * @param {string} inputKey
  94. * @returns {string}
  95. */
  96. detectKeyFormat(inputKey) {
  97. const hexPattern = new RegExp(/^(?:[\dA-Fa-f]{2}[ ,;:]?)+$/);
  98. const b64Pattern = new RegExp(/^\s*(?:[A-Za-z\d+/]{4})+(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?\s*$/);
  99. if (hexPattern.test(inputKey)) {
  100. return "Hex";
  101. } else if (b64Pattern.test(inputKey)) {
  102. return "Base64";
  103. } else {
  104. throw new OperationError("Unable to detect input key format.");
  105. }
  106. }
  107. /**
  108. * Parses fields from the key
  109. *
  110. * @param {byteArray} key
  111. */
  112. parseKey(key) {
  113. const fields = [];
  114. while (key.length > 0) {
  115. const lengthField = key.slice(0, 4);
  116. let decodedLength = 0;
  117. for (let i = 0; i < lengthField.length; i++) {
  118. decodedLength += lengthField[i];
  119. decodedLength = decodedLength << 8;
  120. }
  121. decodedLength = decodedLength >> 8;
  122. // Break if length wasn't decoded correctly
  123. if (decodedLength <= 0) break;
  124. fields.push(toHexFast(key.slice(4, 4 + decodedLength)));
  125. key = key.slice(4 + decodedLength);
  126. }
  127. return fields;
  128. }
  129. }
  130. export default ParseSSHHostKey;