8533c1f67a680ba73839ec5e03f7d47a8938c3e045e5a84f8efc7d72f15bd9e69bf66b9af831d0496d5a8a4f6e65fe13c57f71ad582a4e170b7a4c26cf8220 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. 'use strict';
  2. var BN = require('bn.js');
  3. var utils = require('../utils');
  4. var assert = utils.assert;
  5. function Signature(options, enc) {
  6. if (options instanceof Signature)
  7. return options;
  8. if (this._importDER(options, enc))
  9. return;
  10. assert(options.r && options.s, 'Signature without r or s');
  11. this.r = new BN(options.r, 16);
  12. this.s = new BN(options.s, 16);
  13. if (options.recoveryParam === undefined)
  14. this.recoveryParam = null;
  15. else
  16. this.recoveryParam = options.recoveryParam;
  17. }
  18. module.exports = Signature;
  19. function Position() {
  20. this.place = 0;
  21. }
  22. function getLength(buf, p) {
  23. var initial = buf[p.place++];
  24. if (!(initial & 0x80)) {
  25. return initial;
  26. }
  27. var octetLen = initial & 0xf;
  28. // Indefinite length or overflow
  29. if (octetLen === 0 || octetLen > 4) {
  30. return false;
  31. }
  32. if(buf[p.place] === 0x00) {
  33. return false;
  34. }
  35. var val = 0;
  36. for (var i = 0, off = p.place; i < octetLen; i++, off++) {
  37. val <<= 8;
  38. val |= buf[off];
  39. val >>>= 0;
  40. }
  41. // Leading zeroes
  42. if (val <= 0x7f) {
  43. return false;
  44. }
  45. p.place = off;
  46. return val;
  47. }
  48. function rmPadding(buf) {
  49. var i = 0;
  50. var len = buf.length - 1;
  51. while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) {
  52. i++;
  53. }
  54. if (i === 0) {
  55. return buf;
  56. }
  57. return buf.slice(i);
  58. }
  59. Signature.prototype._importDER = function _importDER(data, enc) {
  60. data = utils.toArray(data, enc);
  61. var p = new Position();
  62. if (data[p.place++] !== 0x30) {
  63. return false;
  64. }
  65. var len = getLength(data, p);
  66. if (len === false) {
  67. return false;
  68. }
  69. if ((len + p.place) !== data.length) {
  70. return false;
  71. }
  72. if (data[p.place++] !== 0x02) {
  73. return false;
  74. }
  75. var rlen = getLength(data, p);
  76. if (rlen === false) {
  77. return false;
  78. }
  79. if ((data[p.place] & 128) !== 0) {
  80. return false;
  81. }
  82. var r = data.slice(p.place, rlen + p.place);
  83. p.place += rlen;
  84. if (data[p.place++] !== 0x02) {
  85. return false;
  86. }
  87. var slen = getLength(data, p);
  88. if (slen === false) {
  89. return false;
  90. }
  91. if (data.length !== slen + p.place) {
  92. return false;
  93. }
  94. if ((data[p.place] & 128) !== 0) {
  95. return false;
  96. }
  97. var s = data.slice(p.place, slen + p.place);
  98. if (r[0] === 0) {
  99. if (r[1] & 0x80) {
  100. r = r.slice(1);
  101. } else {
  102. // Leading zeroes
  103. return false;
  104. }
  105. }
  106. if (s[0] === 0) {
  107. if (s[1] & 0x80) {
  108. s = s.slice(1);
  109. } else {
  110. // Leading zeroes
  111. return false;
  112. }
  113. }
  114. this.r = new BN(r);
  115. this.s = new BN(s);
  116. this.recoveryParam = null;
  117. return true;
  118. };
  119. function constructLength(arr, len) {
  120. if (len < 0x80) {
  121. arr.push(len);
  122. return;
  123. }
  124. var octets = 1 + (Math.log(len) / Math.LN2 >>> 3);
  125. arr.push(octets | 0x80);
  126. while (--octets) {
  127. arr.push((len >>> (octets << 3)) & 0xff);
  128. }
  129. arr.push(len);
  130. }
  131. Signature.prototype.toDER = function toDER(enc) {
  132. var r = this.r.toArray();
  133. var s = this.s.toArray();
  134. // Pad values
  135. if (r[0] & 0x80)
  136. r = [ 0 ].concat(r);
  137. // Pad values
  138. if (s[0] & 0x80)
  139. s = [ 0 ].concat(s);
  140. r = rmPadding(r);
  141. s = rmPadding(s);
  142. while (!s[0] && !(s[1] & 0x80)) {
  143. s = s.slice(1);
  144. }
  145. var arr = [ 0x02 ];
  146. constructLength(arr, r.length);
  147. arr = arr.concat(r);
  148. arr.push(0x02);
  149. constructLength(arr, s.length);
  150. var backHalf = arr.concat(s);
  151. var res = [ 0x30 ];
  152. constructLength(res, backHalf.length);
  153. res = res.concat(backHalf);
  154. return utils.encode(res, enc);
  155. };