JSEncryptRSAKey.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = function (d, b) {
  3. extendStatics = Object.setPrototypeOf ||
  4. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  5. function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
  6. return extendStatics(d, b);
  7. };
  8. return function (d, b) {
  9. if (typeof b !== "function" && b !== null)
  10. throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
  11. extendStatics(d, b);
  12. function __() { this.constructor = d; }
  13. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  14. };
  15. })();
  16. import { hex2b64 } from "./lib/jsbn/base64";
  17. import { Hex } from "./lib/asn1js/hex";
  18. import { Base64 } from "./lib/asn1js/base64";
  19. import { ASN1 } from "./lib/asn1js/asn1";
  20. import { RSAKey } from "./lib/jsbn/rsa";
  21. import { parseBigInt } from "./lib/jsbn/jsbn";
  22. import { KJUR } from "./lib/jsrsasign/asn1-1.0";
  23. /**
  24. * Create a new JSEncryptRSAKey that extends Tom Wu's RSA key object.
  25. * This object is just a decorator for parsing the key parameter
  26. * @param {string|Object} key - The key in string format, or an object containing
  27. * the parameters needed to build a RSAKey object.
  28. * @constructor
  29. */
  30. var JSEncryptRSAKey = /** @class */ (function (_super) {
  31. __extends(JSEncryptRSAKey, _super);
  32. function JSEncryptRSAKey(key) {
  33. var _this = _super.call(this) || this;
  34. // Call the super constructor.
  35. // RSAKey.call(this);
  36. // If a key key was provided.
  37. if (key) {
  38. // If this is a string...
  39. if (typeof key === "string") {
  40. _this.parseKey(key);
  41. }
  42. else if (JSEncryptRSAKey.hasPrivateKeyProperty(key) ||
  43. JSEncryptRSAKey.hasPublicKeyProperty(key)) {
  44. // Set the values for the key.
  45. _this.parsePropertiesFrom(key);
  46. }
  47. }
  48. return _this;
  49. }
  50. /**
  51. * Method to parse a pem encoded string containing both a public or private key.
  52. * The method will translate the pem encoded string in a der encoded string and
  53. * will parse private key and public key parameters. This method accepts public key
  54. * in the rsaencryption pkcs #1 format (oid: 1.2.840.113549.1.1.1).
  55. *
  56. * @todo Check how many rsa formats use the same format of pkcs #1.
  57. *
  58. * The format is defined as:
  59. * PublicKeyInfo ::= SEQUENCE {
  60. * algorithm AlgorithmIdentifier,
  61. * PublicKey BIT STRING
  62. * }
  63. * Where AlgorithmIdentifier is:
  64. * AlgorithmIdentifier ::= SEQUENCE {
  65. * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm
  66. * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1)
  67. * }
  68. * and PublicKey is a SEQUENCE encapsulated in a BIT STRING
  69. * RSAPublicKey ::= SEQUENCE {
  70. * modulus INTEGER, -- n
  71. * publicExponent INTEGER -- e
  72. * }
  73. * it's possible to examine the structure of the keys obtained from openssl using
  74. * an asn.1 dumper as the one used here to parse the components: http://lapo.it/asn1js/
  75. * @argument {string} pem the pem encoded string, can include the BEGIN/END header/footer
  76. * @private
  77. */
  78. JSEncryptRSAKey.prototype.parseKey = function (pem) {
  79. try {
  80. var modulus = 0;
  81. var public_exponent = 0;
  82. var reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/;
  83. var der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem);
  84. var asn1 = ASN1.decode(der);
  85. // Fixes a bug with OpenSSL 1.0+ private keys
  86. if (asn1.sub.length === 3) {
  87. asn1 = asn1.sub[2].sub[0];
  88. }
  89. if (asn1.sub.length === 9) {
  90. // Parse the private key.
  91. modulus = asn1.sub[1].getHexStringValue(); // bigint
  92. this.n = parseBigInt(modulus, 16);
  93. public_exponent = asn1.sub[2].getHexStringValue(); // int
  94. this.e = parseInt(public_exponent, 16);
  95. var private_exponent = asn1.sub[3].getHexStringValue(); // bigint
  96. this.d = parseBigInt(private_exponent, 16);
  97. var prime1 = asn1.sub[4].getHexStringValue(); // bigint
  98. this.p = parseBigInt(prime1, 16);
  99. var prime2 = asn1.sub[5].getHexStringValue(); // bigint
  100. this.q = parseBigInt(prime2, 16);
  101. var exponent1 = asn1.sub[6].getHexStringValue(); // bigint
  102. this.dmp1 = parseBigInt(exponent1, 16);
  103. var exponent2 = asn1.sub[7].getHexStringValue(); // bigint
  104. this.dmq1 = parseBigInt(exponent2, 16);
  105. var coefficient = asn1.sub[8].getHexStringValue(); // bigint
  106. this.coeff = parseBigInt(coefficient, 16);
  107. }
  108. else if (asn1.sub.length === 2) {
  109. if (asn1.sub[0].sub) {
  110. // Parse ASN.1 SubjectPublicKeyInfo type as defined by X.509
  111. var bit_string = asn1.sub[1];
  112. var sequence = bit_string.sub[0];
  113. modulus = sequence.sub[0].getHexStringValue();
  114. this.n = parseBigInt(modulus, 16);
  115. public_exponent = sequence.sub[1].getHexStringValue();
  116. this.e = parseInt(public_exponent, 16);
  117. }
  118. else {
  119. // Parse ASN.1 RSAPublicKey type as defined by PKCS #1
  120. modulus = asn1.sub[0].getHexStringValue();
  121. this.n = parseBigInt(modulus, 16);
  122. public_exponent = asn1.sub[1].getHexStringValue();
  123. this.e = parseInt(public_exponent, 16);
  124. }
  125. }
  126. else {
  127. return false;
  128. }
  129. return true;
  130. }
  131. catch (ex) {
  132. return false;
  133. }
  134. };
  135. /**
  136. * Translate rsa parameters in a hex encoded string representing the rsa key.
  137. *
  138. * The translation follow the ASN.1 notation :
  139. * RSAPrivateKey ::= SEQUENCE {
  140. * version Version,
  141. * modulus INTEGER, -- n
  142. * publicExponent INTEGER, -- e
  143. * privateExponent INTEGER, -- d
  144. * prime1 INTEGER, -- p
  145. * prime2 INTEGER, -- q
  146. * exponent1 INTEGER, -- d mod (p1)
  147. * exponent2 INTEGER, -- d mod (q-1)
  148. * coefficient INTEGER, -- (inverse of q) mod p
  149. * }
  150. * @returns {string} DER Encoded String representing the rsa private key
  151. * @private
  152. */
  153. JSEncryptRSAKey.prototype.getPrivateBaseKey = function () {
  154. var options = {
  155. array: [
  156. new KJUR.asn1.DERInteger({ int: 0 }),
  157. new KJUR.asn1.DERInteger({ bigint: this.n }),
  158. new KJUR.asn1.DERInteger({ int: this.e }),
  159. new KJUR.asn1.DERInteger({ bigint: this.d }),
  160. new KJUR.asn1.DERInteger({ bigint: this.p }),
  161. new KJUR.asn1.DERInteger({ bigint: this.q }),
  162. new KJUR.asn1.DERInteger({ bigint: this.dmp1 }),
  163. new KJUR.asn1.DERInteger({ bigint: this.dmq1 }),
  164. new KJUR.asn1.DERInteger({ bigint: this.coeff }),
  165. ],
  166. };
  167. var seq = new KJUR.asn1.DERSequence(options);
  168. return seq.getEncodedHex();
  169. };
  170. /**
  171. * base64 (pem) encoded version of the DER encoded representation
  172. * @returns {string} pem encoded representation without header and footer
  173. * @public
  174. */
  175. JSEncryptRSAKey.prototype.getPrivateBaseKeyB64 = function () {
  176. return hex2b64(this.getPrivateBaseKey());
  177. };
  178. /**
  179. * Translate rsa parameters in a hex encoded string representing the rsa public key.
  180. * The representation follow the ASN.1 notation :
  181. * PublicKeyInfo ::= SEQUENCE {
  182. * algorithm AlgorithmIdentifier,
  183. * PublicKey BIT STRING
  184. * }
  185. * Where AlgorithmIdentifier is:
  186. * AlgorithmIdentifier ::= SEQUENCE {
  187. * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm
  188. * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1)
  189. * }
  190. * and PublicKey is a SEQUENCE encapsulated in a BIT STRING
  191. * RSAPublicKey ::= SEQUENCE {
  192. * modulus INTEGER, -- n
  193. * publicExponent INTEGER -- e
  194. * }
  195. * @returns {string} DER Encoded String representing the rsa public key
  196. * @private
  197. */
  198. JSEncryptRSAKey.prototype.getPublicBaseKey = function () {
  199. var first_sequence = new KJUR.asn1.DERSequence({
  200. array: [
  201. new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }),
  202. new KJUR.asn1.DERNull(),
  203. ],
  204. });
  205. var second_sequence = new KJUR.asn1.DERSequence({
  206. array: [
  207. new KJUR.asn1.DERInteger({ bigint: this.n }),
  208. new KJUR.asn1.DERInteger({ int: this.e }),
  209. ],
  210. });
  211. var bit_string = new KJUR.asn1.DERBitString({
  212. hex: "00" + second_sequence.getEncodedHex(),
  213. });
  214. var seq = new KJUR.asn1.DERSequence({
  215. array: [first_sequence, bit_string],
  216. });
  217. return seq.getEncodedHex();
  218. };
  219. /**
  220. * base64 (pem) encoded version of the DER encoded representation
  221. * @returns {string} pem encoded representation without header and footer
  222. * @public
  223. */
  224. JSEncryptRSAKey.prototype.getPublicBaseKeyB64 = function () {
  225. return hex2b64(this.getPublicBaseKey());
  226. };
  227. /**
  228. * wrap the string in block of width chars. The default value for rsa keys is 64
  229. * characters.
  230. * @param {string} str the pem encoded string without header and footer
  231. * @param {Number} [width=64] - the length the string has to be wrapped at
  232. * @returns {string}
  233. * @private
  234. */
  235. JSEncryptRSAKey.wordwrap = function (str, width) {
  236. width = width || 64;
  237. if (!str) {
  238. return str;
  239. }
  240. var regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
  241. return str.match(RegExp(regex, "g")).join("\n");
  242. };
  243. /**
  244. * Retrieve the pem encoded private key
  245. * @returns {string} the pem encoded private key with header/footer
  246. * @public
  247. */
  248. JSEncryptRSAKey.prototype.getPrivateKey = function () {
  249. var key = "-----BEGIN RSA PRIVATE KEY-----\n";
  250. key += JSEncryptRSAKey.wordwrap(this.getPrivateBaseKeyB64()) + "\n";
  251. key += "-----END RSA PRIVATE KEY-----";
  252. return key;
  253. };
  254. /**
  255. * Retrieve the pem encoded public key
  256. * @returns {string} the pem encoded public key with header/footer
  257. * @public
  258. */
  259. JSEncryptRSAKey.prototype.getPublicKey = function () {
  260. var key = "-----BEGIN PUBLIC KEY-----\n";
  261. key += JSEncryptRSAKey.wordwrap(this.getPublicBaseKeyB64()) + "\n";
  262. key += "-----END PUBLIC KEY-----";
  263. return key;
  264. };
  265. /**
  266. * Check if the object contains the necessary parameters to populate the rsa modulus
  267. * and public exponent parameters.
  268. * @param {Object} [obj={}] - An object that may contain the two public key
  269. * parameters
  270. * @returns {boolean} true if the object contains both the modulus and the public exponent
  271. * properties (n and e)
  272. * @todo check for types of n and e. N should be a parseable bigInt object, E should
  273. * be a parseable integer number
  274. * @private
  275. */
  276. JSEncryptRSAKey.hasPublicKeyProperty = function (obj) {
  277. obj = obj || {};
  278. return obj.hasOwnProperty("n") && obj.hasOwnProperty("e");
  279. };
  280. /**
  281. * Check if the object contains ALL the parameters of an RSA key.
  282. * @param {Object} [obj={}] - An object that may contain nine rsa key
  283. * parameters
  284. * @returns {boolean} true if the object contains all the parameters needed
  285. * @todo check for types of the parameters all the parameters but the public exponent
  286. * should be parseable bigint objects, the public exponent should be a parseable integer number
  287. * @private
  288. */
  289. JSEncryptRSAKey.hasPrivateKeyProperty = function (obj) {
  290. obj = obj || {};
  291. return (obj.hasOwnProperty("n") &&
  292. obj.hasOwnProperty("e") &&
  293. obj.hasOwnProperty("d") &&
  294. obj.hasOwnProperty("p") &&
  295. obj.hasOwnProperty("q") &&
  296. obj.hasOwnProperty("dmp1") &&
  297. obj.hasOwnProperty("dmq1") &&
  298. obj.hasOwnProperty("coeff"));
  299. };
  300. /**
  301. * Parse the properties of obj in the current rsa object. Obj should AT LEAST
  302. * include the modulus and public exponent (n, e) parameters.
  303. * @param {Object} obj - the object containing rsa parameters
  304. * @private
  305. */
  306. JSEncryptRSAKey.prototype.parsePropertiesFrom = function (obj) {
  307. this.n = obj.n;
  308. this.e = obj.e;
  309. if (obj.hasOwnProperty("d")) {
  310. this.d = obj.d;
  311. this.p = obj.p;
  312. this.q = obj.q;
  313. this.dmp1 = obj.dmp1;
  314. this.dmq1 = obj.dmq1;
  315. this.coeff = obj.coeff;
  316. }
  317. };
  318. return JSEncryptRSAKey;
  319. }(RSAKey));
  320. export { JSEncryptRSAKey };