RSA.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. * Copyright (c) 2015 Eric Wilde.
  3. * Copyright 1998-2015 David Shapiro.
  4. *
  5. * RSA.js is a suite of routines for performing RSA public-key computations
  6. * in JavaScript. The cryptographic functions herein are used for encoding
  7. * and decoding strings to be sent over unsecure channels.
  8. *
  9. * To use these routines, a pair of public/private keys is created through a
  10. * number of means (OpenSSL tools on Linux/Unix, Dave Shapiro's
  11. * RSAKeyGenerator program on Windows). These keys are passed to RSAKeyPair
  12. * as hexadecimal strings to create an encryption key object. This key object
  13. * is then used with encryptedString to encrypt blocks of plaintext using the
  14. * public key. The resulting cyphertext blocks can be decrypted with
  15. * decryptedString.
  16. *
  17. * Note that the cryptographic functions herein are complementary to those
  18. * found in CryptoFuncs.php and CryptoFuncs.pm. Hence, encrypted messages may
  19. * be sent between programs written in any of those languages. The most
  20. * useful, of course is to send messages encrypted by a Web page using RSA.js
  21. * to a PHP or Perl script running on a Web servitron.
  22. *
  23. * Also, the optional padding flag may be specified on the call to
  24. * encryptedString, in which case blocks of cyphertext that are compatible
  25. * with real crypto libraries such as OpenSSL or Microsoft will be created.
  26. * These blocks of cyphertext can then be sent to Web servitron that uses one
  27. * of these crypto libraries for decryption. This allows messages encrypted
  28. * with longer keys to be decrypted quickly on the Web server as well as
  29. * making for more secure communications when a padding algorithm such as
  30. * PKCS1v1.5 is used.
  31. *
  32. * These routines require BigInt.js and Barrett.js.
  33. */
  34. /*****************************************************************************/
  35. /*
  36. * Modifications
  37. * -------------
  38. *
  39. * 2014 Jan 11 E. Wilde Add optional padding flag to encryptedString
  40. * for compatibility with real crypto libraries
  41. * such as OpenSSL or Microsoft. Add PKCS1v1.5
  42. * padding.
  43. *
  44. * 2015 Jan 5 D. Shapiro Add optional encoding flag for encryptedString
  45. * and encapsulate padding and encoding constants
  46. * in RSAAPP object.
  47. *
  48. * Original Code
  49. * -------------
  50. *
  51. * Copyright 1998-2005 David Shapiro.
  52. *
  53. * You may use, re-use, abuse, copy, and modify this code to your liking, but
  54. * please keep this header.
  55. *
  56. * Thanks!
  57. *
  58. * Dave Shapiro
  59. * dave@ohdave.com
  60. */
  61. /*****************************************************************************/
  62. const BigInt = require("./BigInt");
  63. const Barrett = require("./Barrett");
  64. // const bigInt = require("./BigInt");
  65. // console.log(bigInt,biFromHex)
  66. var bigInt = BigInt.bigInt
  67. var biFromHex = BigInt.biFromHex
  68. var biHighIndex = BigInt.biHighIndex
  69. var BarrettMu = Barrett.BarrettMu
  70. var RSAAPP = {};
  71. RSAAPP.NoPadding = "NoPadding";
  72. RSAAPP.PKCS1Padding = "PKCS1Padding";
  73. RSAAPP.RawEncoding = "RawEncoding";
  74. RSAAPP.NumericEncoding = "NumericEncoding"
  75. /*****************************************************************************/
  76. function RSAKeyPair(encryptionExponent, decryptionExponent, modulus, keylen)
  77. /*
  78. * encryptionExponent The encryption exponent (i.e. public
  79. * encryption key) to be used for
  80. * encrypting messages. If you aren't
  81. * doing any encrypting, a dummy
  82. * exponent such as "10001" can be
  83. * passed.
  84. *
  85. * decryptionExponent The decryption exponent (i.e. private
  86. * decryption key) to be used for
  87. * decrypting messages. If you aren't
  88. * doing any decrypting, a dummy
  89. * exponent such as "10001" can be
  90. * passed.
  91. *
  92. * modulus The modulus to be used both for
  93. * encrypting and decrypting messages.
  94. *
  95. * keylen The optional length of the key, in
  96. * bits. If omitted, RSAKeyPair will
  97. * attempt to derive a key length (but,
  98. * see the notes below).
  99. *
  100. * returns The "new" object creator returns an
  101. * instance of a key object that can be
  102. * used to encrypt/decrypt messages.
  103. *
  104. * This routine is invoked as the first step in the encryption or decryption
  105. * process to take the three numbers (expressed as hexadecimal strings) that
  106. * are used for RSA asymmetric encryption/decryption and turn them into a key
  107. * object that can be used for encrypting and decrypting.
  108. *
  109. * The key object is created thusly:
  110. *
  111. * RSAKey = new RSAKeyPair("ABC12345", 10001, "987654FE");
  112. *
  113. * or:
  114. *
  115. * RSAKey = new RSAKeyPair("ABC12345", 10001, "987654FE", 64);
  116. *
  117. * Note that RSAKeyPair will try to derive the length of the key that is being
  118. * used, from the key itself. The key length is especially useful when one of
  119. * the padding options is used and/or when the encrypted messages created by
  120. * the routine encryptedString are exchanged with a real crypto library such
  121. * as OpenSSL or Microsoft, as it determines how many padding characters are
  122. * appended.
  123. *
  124. * Usually, RSAKeyPair can determine the key length from the modulus of the
  125. * key but this doesn't always work properly, depending on the actual value of
  126. * the modulus. If you are exchanging messages with a real crypto library,
  127. * such as OpenSSL or Microsoft, that depends on the fact that the blocks
  128. * being passed to it are properly padded, you'll want the key length to be
  129. * set properly. If that's the case, of if you just want to be sure, you
  130. * should specify the key length that you used to generated the key, in bits
  131. * when this routine is invoked.
  132. */
  133. {
  134. /*
  135. * Convert from hexadecimal and save the encryption/decryption exponents and
  136. * modulus as big integers in the key object.
  137. */
  138. this.e = biFromHex(encryptionExponent);
  139. this.d = biFromHex(decryptionExponent);
  140. this.m = biFromHex(modulus);
  141. /*
  142. * Using big integers, we can represent two bytes per element in the big
  143. * integer array, so we calculate the chunk size as:
  144. *
  145. * chunkSize = 2 * (number of digits in modulus - 1)
  146. *
  147. * Since biHighIndex returns the high index, not the number of digits, the
  148. * number 1 has already been subtracted from its answer.
  149. *
  150. * However, having said all this, "User Knows Best". If our caller passes us
  151. * a key length (in bits), we'll treat it as gospel truth.
  152. */
  153. if (typeof(keylen) != 'number') { this.chunkSize = 2 * biHighIndex(this.m); }
  154. else { this.chunkSize = keylen / 8; }
  155. this.radix = 16;
  156. /*
  157. * Precalculate the stuff used for Barrett modular reductions.
  158. */
  159. this.barrett = new BarrettMu(this.m);
  160. }
  161. /*****************************************************************************/
  162. function encryptedString(key, s, pad, encoding)
  163. /*
  164. * key The previously-built RSA key whose
  165. * public key component is to be used to
  166. * encrypt the plaintext string.
  167. *
  168. * s The plaintext string that is to be
  169. * encrypted, using the RSA assymmetric
  170. * encryption method.
  171. *
  172. * pad The optional padding method to use
  173. * when extending the plaintext to the
  174. * full chunk size required by the RSA
  175. * algorithm. To maintain compatibility
  176. * with other crypto libraries, the
  177. * padding method is described by a
  178. * string. The default, if not
  179. * specified is "OHDave". Here are the
  180. * choices:
  181. *
  182. * OHDave - this is the original
  183. * padding method employed by Dave
  184. * Shapiro and Rob Saunders. If
  185. * this method is chosen, the
  186. * plaintext can be of any length.
  187. * It will be padded to the correct
  188. * length with zeros and then broken
  189. * up into chunks of the correct
  190. * length before being encrypted.
  191. * The resultant cyphertext blocks
  192. * will be separated by blanks.
  193. *
  194. * Note that the original code by
  195. * Dave Shapiro reverses the byte
  196. * order to little-endian, as the
  197. * plaintext is encrypted. If
  198. * either these JavaScript routines
  199. * or one of the complementary
  200. * PHP/Perl routines derived from
  201. * this code is used for decryption,
  202. * the byte order will be reversed
  203. * again upon decryption so as to
  204. * come out correctly.
  205. *
  206. * Also note that this padding
  207. * method is claimed to be less
  208. * secure than PKCS1Padding.
  209. *
  210. * NoPadding - this method truncates
  211. * the plaintext to the length of
  212. * the RSA key, if it is longer. If
  213. * its length is shorter, it is
  214. * padded with zeros. In either
  215. * case, the plaintext string is
  216. * reversed to preserve big-endian
  217. * order before it is encrypted to
  218. * maintain compatibility with real
  219. * crypto libraries such as OpenSSL
  220. * or Microsoft. When the
  221. * cyphertext is to be decrypted
  222. * by a crypto library, the
  223. * library routine's RSAAPP.NoPadding
  224. * flag, or its equivalent, should
  225. * be used.
  226. *
  227. * Note that this padding method is
  228. * claimed to be less secure than
  229. * PKCS1Padding.
  230. *
  231. * PKCS1Padding - the PKCS1v1.5
  232. * padding method (as described in
  233. * RFC 2313) is employed to pad the
  234. * plaintext string. The plaintext
  235. * string must be no longer than the
  236. * length of the RSA key minus 11,
  237. * since PKCS1v1.5 requires 3 bytes
  238. * of overhead and specifies a
  239. * minimum pad of 8 bytes. The
  240. * plaintext string is padded with
  241. * randomly-generated bytes and then
  242. * its order is reversed to preserve
  243. * big-endian order before it is
  244. * encrypted to maintain
  245. * compatibility with real crypto
  246. * libraries such as OpenSSL or
  247. * Microsoft. When the cyphertext
  248. * is to be decrypted by a crypto
  249. * library, the library routine's
  250. * RSAAPP.PKCS1Padding flag, or its
  251. * equivalent, should be used.
  252. *
  253. * encoding The optional encoding scheme to use
  254. * for the return value. If ommitted,
  255. * numeric encoding will be used.
  256. *
  257. * RawEncoding - The return value
  258. * is given as its raw value.
  259. * This is the easiest method when
  260. * interoperating with server-side
  261. * OpenSSL, as no additional conversion
  262. * is required. Use the constant
  263. * RSAAPP.RawEncoding for this option.
  264. *
  265. * NumericEncoding - The return value
  266. * is given as a number in hexadecimal.
  267. * Perhaps useful for debugging, but
  268. * will need to be translated back to
  269. * its raw equivalent (e.g. using
  270. * PHP's hex2bin) before using with
  271. * OpenSSL. Use the constant
  272. * RSAAPP.NumericEncoding for this option.
  273. *
  274. * returns The cyphertext block that results
  275. * from encrypting the plaintext string
  276. * s with the RSA key.
  277. *
  278. * This routine accepts a plaintext string that is to be encrypted with the
  279. * public key component of the previously-built RSA key using the RSA
  280. * assymmetric encryption method. Before it is encrypted, the plaintext
  281. * string is padded to the same length as the encryption key for proper
  282. * encryption.
  283. *
  284. * Depending on the padding method chosen, an optional header with block type
  285. * is prepended, the plaintext is padded using zeros or randomly-generated
  286. * bytes, and then the plaintext is possibly broken up into chunks.
  287. *
  288. * Note that, for padding with zeros, this routine was altered by Rob Saunders
  289. * (rob@robsaunders.net). The new routine pads the string after it has been
  290. * converted to an array. This fixes an incompatibility with Flash MX's
  291. * ActionScript.
  292. *
  293. * The various padding schemes employed by this routine, and as presented to
  294. * RSA for encryption, are shown below. Note that the RSA encryption done
  295. * herein reverses the byte order as encryption is done:
  296. *
  297. * Plaintext In
  298. * ------------
  299. *
  300. * d5 d4 d3 d2 d1 d0
  301. *
  302. * OHDave
  303. * ------
  304. *
  305. * d5 d4 d3 d2 d1 d0 00 00 00 /.../ 00 00 00 00 00 00 00 00
  306. *
  307. * NoPadding
  308. * ---------
  309. *
  310. * 00 00 00 00 00 00 00 00 00 /.../ 00 00 d0 d1 d2 d3 d4 d5
  311. *
  312. * PKCS1Padding
  313. * ------------
  314. *
  315. * d0 d1 d2 d3 d4 d5 00 p0 p1 /.../ p2 p3 p4 p5 p6 p7 02 00
  316. * \------------ ------------/
  317. * \/
  318. * Minimum 8 bytes pad length
  319. */
  320. {
  321. var a = new Array(); // The usual Alice and Bob stuff
  322. var sl = s.length; // Plaintext string length
  323. var i, j, k; // The usual Fortran index stuff
  324. var padtype; // Type of padding to do
  325. var encodingtype; // Type of output encoding
  326. var rpad; // Random pad
  327. var al; // Array length
  328. var result = ""; // Cypthertext result
  329. var block; // Big integer block to encrypt
  330. var crypt; // Big integer result
  331. var text; // Text result
  332. /*
  333. * Figure out the padding type.
  334. */
  335. if (typeof(pad) == 'string') {
  336. if (pad == RSAAPP.NoPadding) { padtype = 1; }
  337. else if (pad == RSAAPP.PKCS1Padding) { padtype = 2; }
  338. else { padtype = 0; }
  339. }
  340. else { padtype = 0; }
  341. /*
  342. * Determine encoding type.
  343. */
  344. if (typeof(encoding) == 'string' && encoding == RSAAPP.RawEncoding) {
  345. encodingtype = 1;
  346. }
  347. else { encodingtype = 0; }
  348. /*
  349. * If we're not using Dave's padding method, we need to truncate long
  350. * plaintext blocks to the correct length for the padding method used:
  351. *
  352. * NoPadding - key length
  353. * PKCS1Padding - key length - 11
  354. */
  355. if (padtype == 1) {
  356. if (sl > key.chunkSize) { sl = key.chunkSize; }
  357. }
  358. else if (padtype == 2) {
  359. if (sl > (key.chunkSize-11)) { sl = key.chunkSize - 11; }
  360. }
  361. /*
  362. * Convert the plaintext string to an array of characters so that we can work
  363. * with individual characters.
  364. *
  365. * Note that, if we're talking to a real crypto library at the other end, we
  366. * reverse the plaintext order to preserve big-endian order.
  367. */
  368. i = 0;
  369. if (padtype == 2) { j = sl - 1; }
  370. else { j = key.chunkSize - 1; }
  371. while (i < sl) {
  372. if (padtype) { a[j] = s.charCodeAt(i); }
  373. else { a[i] = s.charCodeAt(i); }
  374. i++; j--;
  375. }
  376. /*
  377. * Now is the time to add the padding.
  378. *
  379. * If we're doing PKCS1v1.5 padding, we pick up padding where we left off and
  380. * pad the remainder of the block. Otherwise, we pad at the front of the
  381. * block. This gives us the correct padding for big-endian blocks.
  382. *
  383. * The padding is either a zero byte or a randomly-generated non-zero byte.
  384. */
  385. if (padtype == 1) { i = 0; }
  386. j = key.chunkSize - (sl % key.chunkSize);
  387. while (j > 0) {
  388. if (padtype == 2) {
  389. rpad = Math.floor(Math.random() * 256);
  390. while (!rpad) { rpad = Math.floor(Math.random() * 256); }
  391. a[i] = rpad;
  392. }
  393. else { a[i] = 0; }
  394. i++; j--;
  395. }
  396. /*
  397. * For PKCS1v1.5 padding, we need to fill in the block header.
  398. *
  399. * According to RFC 2313, a block type, a padding string, and the data shall
  400. * be formatted into the encryption block:
  401. *
  402. * EncrBlock = 00 || BlockType || PadString || 00 || Data
  403. *
  404. * The block type shall be a single octet indicating the structure of the
  405. * encryption block. For this version of the document it shall have value 00,
  406. * 01, or 02. For a private-key operation, the block type shall be 00 or 01.
  407. * For a public-key operation, it shall be 02.
  408. *
  409. * The padding string shall consist of enough octets to pad the encryption
  410. * block to the length of the encryption key. For block type 00, the octets
  411. * shall have value 00; for block type 01, they shall have value FF; and for
  412. * block type 02, they shall be pseudorandomly generated and nonzero.
  413. *
  414. * Note that in a previous step, we wrote padding bytes into the first three
  415. * bytes of the encryption block because it was simpler to do so. We now
  416. * overwrite them.
  417. */
  418. if (padtype == 2)
  419. {
  420. a[sl] = 0;
  421. a[key.chunkSize-2] = 2;
  422. a[key.chunkSize-1] = 0;
  423. }
  424. /*
  425. * Carve up the plaintext and encrypt each of the resultant blocks.
  426. */
  427. al = a.length;
  428. for (i = 0; i < al; i += key.chunkSize) {
  429. /*
  430. * Get a block.
  431. */
  432. block = new bigInt();
  433. j = 0;
  434. for (k = i; k < (i+key.chunkSize); ++j) {
  435. block.digits[j] = a[k++];
  436. block.digits[j] += a[k++] << 8;
  437. }
  438. /*
  439. * Encrypt it, convert it to text, and append it to the result.
  440. */
  441. crypt = key.barrett.powMod(block, key.e);
  442. if (encodingtype == 1) {
  443. text = biToBytes(crypt);
  444. }
  445. else {
  446. text = (key.radix == 16) ? biToHex(crypt) : biToString(crypt, key.radix);
  447. }
  448. result += text;
  449. }
  450. /*
  451. * Return the result, removing the last space.
  452. */
  453. //result = (result.substring(0, result.length - 1));
  454. return result;
  455. }
  456. /*****************************************************************************/
  457. function decryptedString(key, c)
  458. /*
  459. * key The previously-built RSA key whose
  460. * private key component is to be used
  461. * to decrypt the cyphertext string.
  462. *
  463. * c The cyphertext string that is to be
  464. * decrypted, using the RSA assymmetric
  465. * encryption method.
  466. *
  467. * returns The plaintext block that results from
  468. * decrypting the cyphertext string c
  469. * with the RSA key.
  470. *
  471. * This routine is the complementary decryption routine that is meant to be
  472. * used for JavaScript decryption of cyphertext blocks that were encrypted
  473. * using the OHDave padding method of the encryptedString routine (in this
  474. * module). It can also decrypt cyphertext blocks that were encrypted by
  475. * RSAEncode (in CryptoFuncs.pm or CryptoFuncs.php) so that encrypted
  476. * messages can be sent of insecure links (e.g. HTTP) to a Web page.
  477. *
  478. * It accepts a cyphertext string that is to be decrypted with the public key
  479. * component of the previously-built RSA key using the RSA assymmetric
  480. * encryption method. Multiple cyphertext blocks are broken apart, if they
  481. * are found in c, and each block is decrypted. All of the decrypted blocks
  482. * are concatenated back together to obtain the original plaintext string.
  483. *
  484. * This routine assumes that the plaintext was padded to the same length as
  485. * the encryption key with zeros. Therefore, it removes any zero bytes that
  486. * are found at the end of the last decrypted block, before it is appended to
  487. * the decrypted plaintext string.
  488. *
  489. * Note that the encryptedString routine (in this module) works fairly quickly
  490. * simply by virtue of the fact that the public key most often chosen is quite
  491. * short (e.g. 0x10001). This routine does not have that luxury. The
  492. * decryption key that it must employ is the full key length. For long keys,
  493. * this can result in serious timing delays (e.g. 7-8 seconds to decrypt using
  494. * 2048 bit keys on a reasonably fast machine, under the Firefox Web browser).
  495. *
  496. * If you intend to send encrypted messagess to a JavaScript program running
  497. * under a Web browser, you might consider using shorter keys to keep the
  498. * decryption times low. Alternately, a better scheme is to generate a random
  499. * key for use by a symmetric encryption algorithm and transmit it to the
  500. * other end, after encrypting it with encryptedString. The other end can use
  501. * a real crypto library (e.g. OpenSSL or Microsoft) to decrypt the key and
  502. * then use it to encrypt all of the messages (with a symmetric encryption
  503. * algorithm such as Twofish or AES) bound for the JavaScript program.
  504. * Symmetric decryption is orders of magnitude faster than asymmetric and
  505. * should yield low decryption times, even when executed in JavaScript.
  506. *
  507. * Also note that only the OHDave padding method (e.g. zeros) is supported by
  508. * this routine *AND* that this routine expects little-endian cyphertext, as
  509. * created by the encryptedString routine (in this module) or the RSAEncode
  510. * routine (in either CryptoFuncs.pm or CryptoFuncs.php). You can use one of
  511. * the real crypto libraries to create cyphertext that can be decrypted by
  512. * this routine, if you reverse the plaintext byte order first and then
  513. * manually pad it with zero bytes. The plaintext should then be encrypted
  514. * with the NoPadding flag or its equivalent in the crypto library of your
  515. * choice.
  516. */
  517. {
  518. var blocks = c.split(" "); // Multiple blocks of cyphertext
  519. var b; // The usual Alice and Bob stuff
  520. var i, j; // The usual Fortran index stuff
  521. var bi; // Cyphertext as a big integer
  522. var result = ""; // Plaintext result
  523. /*
  524. * Carve up the cyphertext into blocks.
  525. */
  526. for (i = 0; i < blocks.length; ++i) {
  527. /*
  528. * Depending on the radix being used for the key, convert this cyphertext
  529. * block into a big integer.
  530. */
  531. if (key.radix == 16) { bi = biFromHex(blocks[i]); }
  532. else { bi = biFromString(blocks[i], key.radix); }
  533. /*
  534. * Decrypt the cyphertext.
  535. */
  536. b = key.barrett.powMod(bi, key.d);
  537. /*
  538. * Convert the decrypted big integer back to the plaintext string. Since
  539. * we are using big integers, each element thereof represents two bytes of
  540. * plaintext.
  541. */
  542. for (j = 0; j <= biHighIndex(b); ++j) {
  543. result += String.fromCharCode(b.digits[j] & 255, b.digits[j] >> 8);
  544. }
  545. }
  546. /*
  547. * Remove trailing null, if any.
  548. */
  549. if (result.charCodeAt(result.length - 1) == 0) {
  550. result = result.substring(0, result.length - 1);
  551. }
  552. /*
  553. * Return the plaintext.
  554. */
  555. return (result);
  556. }
  557. // export {RSAKeyPair}
  558. module.exports = RSAKeyPair;