publicEncrypt.js 2.4KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. var parseKeys = require('parse-asn1');
  2. var randomBytes = require('randombytes');
  3. var createHash = require('create-hash');
  4. var mgf = require('./mgf');
  5. var xor = require('./xor');
  6. var bn = require('bn.js');
  7. var withPublic = require('./withPublic');
  8. var crt = require('browserify-rsa');
  9. var constants = {
  10. RSA_PKCS1_OAEP_PADDING: 4,
  11. RSA_PKCS1_PADDIN: 1,
  12. RSA_NO_PADDING: 3
  13. };
  14. module.exports = function publicEncrypt(public_key, msg, reverse) {
  15. var padding;
  16. if (public_key.padding) {
  17. padding = public_key.padding;
  18. } else if (reverse) {
  19. padding = 1;
  20. } else {
  21. padding = 4;
  22. }
  23. var key = parseKeys(public_key);
  24. var paddedMsg;
  25. if (padding === 4) {
  26. paddedMsg = oaep(key, msg);
  27. } else if (padding === 1) {
  28. paddedMsg = pkcs1(key, msg, reverse);
  29. } else if (padding === 3) {
  30. paddedMsg = new bn(msg);
  31. if (paddedMsg.cmp(key.modulus) >= 0) {
  32. throw new Error('data too long for modulus');
  33. }
  34. } else {
  35. throw new Error('unknown padding');
  36. }
  37. if (reverse) {
  38. return crt(paddedMsg, key);
  39. } else {
  40. return withPublic(paddedMsg, key);
  41. }
  42. };
  43. function oaep(key, msg){
  44. var k = key.modulus.byteLength();
  45. var mLen = msg.length;
  46. var iHash = createHash('sha1').update(new Buffer('')).digest();
  47. var hLen = iHash.length;
  48. var hLen2 = 2 * hLen;
  49. if (mLen > k - hLen2 - 2) {
  50. throw new Error('message too long');
  51. }
  52. var ps = new Buffer(k - mLen - hLen2 - 2);
  53. ps.fill(0);
  54. var dblen = k - hLen - 1;
  55. var seed = randomBytes(hLen);
  56. var maskedDb = xor(Buffer.concat([iHash, ps, new Buffer([1]), msg], dblen), mgf(seed, dblen));
  57. var maskedSeed = xor(seed, mgf(maskedDb, hLen));
  58. return new bn(Buffer.concat([new Buffer([0]), maskedSeed, maskedDb], k));
  59. }
  60. function pkcs1(key, msg, reverse){
  61. var mLen = msg.length;
  62. var k = key.modulus.byteLength();
  63. if (mLen > k - 11) {
  64. throw new Error('message too long');
  65. }
  66. var ps;
  67. if (reverse) {
  68. ps = new Buffer(k - mLen - 3);
  69. ps.fill(0xff);
  70. } else {
  71. ps = nonZero(k - mLen - 3);
  72. }
  73. return new bn(Buffer.concat([new Buffer([0, reverse?1:2]), ps, new Buffer([0]), msg], k));
  74. }
  75. function nonZero(len, crypto) {
  76. var out = new Buffer(len);
  77. var i = 0;
  78. var cache = randomBytes(len*2);
  79. var cur = 0;
  80. var num;
  81. while (i < len) {
  82. if (cur === cache.length) {
  83. cache = randomBytes(len*2);
  84. cur = 0;
  85. }
  86. num = cache[cur++];
  87. if (num) {
  88. out[i++] = num;
  89. }
  90. }
  91. return out;
  92. }