input-validator.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. /* jshint node:true */
  9. 'use strict';
  10. var forge = require('node-forge');
  11. var BigInteger = forge.jsbn.BigInteger;
  12. /**
  13. * Input data validation utility for this module. Only intended for internal
  14. * use.
  15. */
  16. module.exports = {
  17. /**
  18. * Checks if a value is defined.
  19. *
  20. * @function checkIsDefined
  21. * @private
  22. * @param {Object}
  23. * value The value to check.
  24. * @param {string}
  25. * label The error message label for the value.
  26. * @throws {TypeError}
  27. * If the value is undefined.
  28. */
  29. checkIsDefined: function(value, label) {
  30. if (typeof value === 'undefined') {
  31. throw new TypeError(label + ' is undefined.');
  32. }
  33. },
  34. /**
  35. * Checks if a value is not null.
  36. *
  37. * @function checkIsNotNull
  38. * @private
  39. * @param {Object}
  40. * value The value to check.
  41. * @param {string}
  42. * label The error message label for the value.
  43. * @throws {TypeError}
  44. * If the value is null.
  45. */
  46. checkIsNotNull: function(value, label) {
  47. if (value === null) {
  48. throw new TypeError(label + ' is null.');
  49. }
  50. },
  51. /**
  52. * Checks if a value is defined and not null.
  53. *
  54. * @function checkIsDefinedAndNotNull
  55. * @private
  56. * @param {Object}
  57. * value The value to check.
  58. * @param {string}
  59. * label The error message label for the value.
  60. * @throws {TypeError}
  61. * If the value is not defined or it is null.
  62. */
  63. checkIsDefinedAndNotNull: function(value, label) {
  64. this.checkIsDefined(value, label);
  65. this.checkIsNotNull(value, label);
  66. },
  67. /**
  68. * Checks if a value is of an expected type.
  69. *
  70. * @function checkIsType
  71. * @private
  72. * @param {Object}
  73. * value The value to check.
  74. * @param {string}
  75. * type The expected type of the value.
  76. * @param {string}
  77. * label The error message label for the value.
  78. * @throws {TypeError}
  79. * If the value is not of the expected type.
  80. */
  81. checkIsType: function(value, type, label) {
  82. var typeFound = typeof value;
  83. if (typeFound !== type) {
  84. throw new TypeError(
  85. 'Expected ' + label + ' to have type \'' + type + '\' ; Found: \'' +
  86. typeFound + '\'');
  87. }
  88. },
  89. /**
  90. * Checks if a value is an instance of an Object.
  91. *
  92. * @function checkIsInstanceOf
  93. * @private
  94. * @param {Object}
  95. * value The value to check.
  96. * @param {Object}
  97. * obj The Object to check against.
  98. * @param {string}
  99. * objName The Object name, for error handling purposes.
  100. * @param {string}
  101. * label The error message label for the value.
  102. * @throws {TypeError}
  103. * If the object is undefined, null, or it is not an instance of
  104. * the Object.
  105. */
  106. checkIsInstanceOf: function(value, obj, objName, label) {
  107. this.checkIsDefinedAndNotNull(value, label);
  108. if (!(value instanceof obj)) {
  109. throw new TypeError(label + ' is not an instance of Object ' + objName);
  110. }
  111. },
  112. /**
  113. * Checks if a value is an object.
  114. *
  115. * @function checkIsObject
  116. * @private
  117. * @param {Object}
  118. * value The value to check.
  119. * @param {string}
  120. * label The error message label for the value.
  121. * @throws {TypeError}
  122. * If the value is not an object.
  123. */
  124. checkIsObject: function(value, label) {
  125. if (typeof value !== 'object') {
  126. throw new TypeError(label + ' is not an object.');
  127. }
  128. },
  129. /**
  130. * Checks if a value is an object and has properties.
  131. *
  132. * @function checkIsObjectWithProperties
  133. * @private
  134. * @param {Object}
  135. * value The value to check.
  136. * @param {string}
  137. * label The error message label for the value.
  138. * @throws {TypeError}
  139. * If the value is not an object or it has no properties.
  140. */
  141. checkIsObjectWithProperties: function(value, label) {
  142. this.checkIsDefinedAndNotNull(value, label);
  143. this.checkIsObject(value, label);
  144. if (!Object.getOwnPropertyNames(value).length) {
  145. throw new TypeError(label + ' does not have any properties.');
  146. }
  147. },
  148. /**
  149. * Checks if a value is a positive number.
  150. *
  151. * @function checkIsPositiveNumber
  152. * @private
  153. * @param {Object}
  154. * value The value to check.
  155. * @param {string}
  156. * label The error message label for the value.
  157. * @throws {TypeError}
  158. * If the value is not a positive number.
  159. */
  160. checkIsPositiveNumber: function(value, label) {
  161. this.checkIsType(value, 'number', label);
  162. if (value === 0 || value < 0) {
  163. throw new TypeError(label + ' must be at least 1. Found: ' + value);
  164. }
  165. },
  166. /**
  167. * Checks if a value is an Array object.
  168. *
  169. * @function checkIsArray
  170. * @private
  171. * @param {Array}
  172. * array The value to check.
  173. * @param {string}
  174. * label The error message label for the value.
  175. * @throws {TypeError}
  176. * If the value is not an Array object.
  177. */
  178. checkIsArray: function(value, label) {
  179. this.checkIsDefinedAndNotNull(value, 'Array of ' + label);
  180. if (value.constructor !== Array) {
  181. throw new TypeError('Array of ' + label + ' is not of type Array.');
  182. }
  183. },
  184. /**
  185. * Checks if a value is a non-empty Array object.
  186. *
  187. * @function checkIsNonEmptyArray
  188. * @private
  189. * @param {Array}
  190. * array The value to check.
  191. * @param {string}
  192. * label The error message label for the value.
  193. * @throws {TypeError}
  194. * If the value is not a non-empty Array object.
  195. */
  196. checkIsNonEmptyArray: function(value, label) {
  197. this.checkIsArray(value, label);
  198. if (value.length < 1) {
  199. throw new TypeError('Array of ' + label + ' is empty.');
  200. }
  201. },
  202. /**
  203. * Checks if a value is a non-empty string.
  204. *
  205. * @function checkIsNonEmptyString
  206. * @private
  207. * @param {string}
  208. * value The value to check.
  209. * @param {string}
  210. * label The error message label for the value.
  211. * @throws {TypeError}
  212. * If the value is not a non-empty string.
  213. */
  214. checkIsNonEmptyString: function(value, label) {
  215. this.checkIsType(value, 'string', label);
  216. if (value.length === 0) {
  217. throw new TypeError(label + ' is empty.');
  218. }
  219. },
  220. /**
  221. * Checks if a value is a BigInteger object.
  222. *
  223. * @function checkIsBigInteger
  224. * @private
  225. * @param {Object}
  226. * value The value to check.
  227. * @param {string}
  228. * label The error message label for the value.
  229. * @throws {TypeError}
  230. * If the value is not a BigInteger object.
  231. */
  232. checkIsBigInteger: function(value, label) {
  233. this.checkIsDefinedAndNotNull(value, label);
  234. if (typeof value.abs === 'undefined') {
  235. throw new TypeError(label + ' is not a BigInteger object.');
  236. }
  237. },
  238. /**
  239. * Checks if a value is a positive BigInteger object.
  240. *
  241. * @function checkIsPositiveBigInteger
  242. * @private
  243. * @param {Object}
  244. * value The value to check.
  245. * @param {string}
  246. * label The error message label for the value.
  247. * @throws {TypeError}
  248. * If the value is not a positive BigInteger object.
  249. */
  250. checkIsPositiveBigInteger: function(value, label) {
  251. this.checkIsBigInteger(value, label);
  252. if (value.compareTo(BigInteger.ONE) < 0) {
  253. throw new TypeError(label + ' must not be less than 1; Found: ' + value);
  254. }
  255. },
  256. /**
  257. * Checks if a value is a valid JSON object.
  258. *
  259. * @function checkIsJsonObject
  260. * @private
  261. * @param {Object}
  262. * value The value to check.
  263. * @param {string}
  264. * label The error message label for the value.
  265. * @throws {TypeError}
  266. * If the value is a valid JSON object.
  267. */
  268. checkIsJsonObject: function(value, label) {
  269. try {
  270. JSON.parse(value);
  271. } catch (error) {
  272. throw new TypeError(label + ' is not a valid JSON object.');
  273. }
  274. },
  275. /**
  276. * Checks if a value is a valid JSON string.
  277. *
  278. * @function checkIsJsonString
  279. * @private
  280. * @param {Object}
  281. * value The value to check.
  282. * @param {string}
  283. * label The error message label for the value.
  284. * @throws {TypeError}
  285. * If the value is a valid JSON string.
  286. */
  287. checkIsJsonString: function(value, label) {
  288. this.checkIsNonEmptyString(value, label);
  289. this.checkIsJsonObject(value, label);
  290. },
  291. /**
  292. * Checks the validity of a Zp subgroup modulus.
  293. *
  294. * @function checkZpSubgroupModulus
  295. * @private
  296. * @param {BigInteger}
  297. * p The modulus to check.
  298. * @param {string}
  299. * label The error message label for the modulus.
  300. * @throws {TypeError}
  301. * If the modulus is not valid.
  302. */
  303. checkZpSubgroupModulus: function(p, label) {
  304. this.checkIsPositiveBigInteger(p, label);
  305. if (p.compareTo(new BigInteger('3')) < 0) {
  306. throw new TypeError(label + ' must not be less than 3; Found: ' + p);
  307. }
  308. },
  309. /**
  310. * Checks the validity of a Zp subgroup order.
  311. *
  312. * @function checkZpSubgroupOrder
  313. * @private
  314. * @param {BigInteger}
  315. * q The order to check.
  316. * @param {string}
  317. * label The error message label for the order.
  318. * @param {BigInteger}
  319. * [p] An optional parameter pertaining to the modulus of the Zp
  320. * subgroup. If this option is provided, the order will be
  321. * checked against this modulus and throw an error if the check
  322. * fails.
  323. * @throws {TypeError}
  324. * If the order is not valid.
  325. */
  326. checkZpSubgroupOrder: function(q, label, p) {
  327. this.checkIsPositiveBigInteger(q, label);
  328. if (typeof p !== 'undefined') {
  329. if (q.compareTo(p) >= 0) {
  330. throw new TypeError(
  331. label + ' must be less than modulus p: ' + p + ' ; Found: ' + q);
  332. }
  333. }
  334. },
  335. /**
  336. * Checks the validity of a Zp subgroup generator.
  337. *
  338. * @function checkZpSubgroupGenerator
  339. * @private
  340. * @param {BigInteger}
  341. * g The generator to check.
  342. * @param {string}
  343. * label The error message label for the generator.
  344. * @param {BigInteger}
  345. * [p] An optional parameter pertaining to the modulus of the Zp
  346. * subgroup. If this option is provided, the generator will be
  347. * checked against this modulus and throw an error if the check
  348. * fails.
  349. * @throws {TypeError}
  350. * If the generator is not valid.
  351. */
  352. checkZpSubgroupGenerator: function(g, label, p) {
  353. this.checkIsPositiveBigInteger(g, label);
  354. if (g.compareTo(new BigInteger('2')) < 0) {
  355. throw new TypeError(label + ' must not be less than 2; Found: ' + g);
  356. }
  357. if (typeof p !== 'undefined' &&
  358. g.compareTo(p) >= 0) {
  359. throw new TypeError(
  360. label + ' must be less than modulus p: ' + p + ' ; Found: ' + g);
  361. }
  362. },
  363. /**
  364. * Checks the validity of a Zp group element value.
  365. *
  366. * @function checkZpGroupElementValue
  367. * @private
  368. * @param {BigInteger}
  369. * value The value to check.
  370. * @param {string}
  371. * label The error message label for the value.
  372. * @param {BigInteger}
  373. * [p] An optional parameter pertaining to the modulus of the Zp
  374. * subgroup. If this option is provided, the generator will be
  375. * checked against this modulus and throw an error if the check
  376. * fails.
  377. * @throws {TypeError}
  378. * If the Zp group element value is not valid.
  379. */
  380. checkZpGroupElementValue: function(value, label, p) {
  381. this.checkIsPositiveBigInteger(value, label);
  382. if (typeof p !== 'undefined' &&
  383. value.compareTo(p) >= 0) {
  384. throw new TypeError(
  385. label + ' must be less than modulus p: ' + p +
  386. ' ; Found: ' + value);
  387. }
  388. },
  389. /**
  390. * Checks the validity of an exponent value.
  391. *
  392. * @function checkExponentValue
  393. * @private
  394. * @param {BigInteger}
  395. * value The value to check.
  396. * @param {string}
  397. * label The error message label for the value.
  398. * @throws {TypeError}
  399. * If the exponent value is not valid.
  400. */
  401. checkExponentValue: function(value, label) {
  402. this.checkIsBigInteger(value, label);
  403. },
  404. /**
  405. * Checks the validity of a ZpGroupElement object.
  406. *
  407. * @function checkZpGroupElement
  408. * @private
  409. * @param {ZpGroupElement}
  410. * element The object to check.
  411. * @param {string}
  412. * label The error message label for the object.
  413. * @param {Zpsubgroup}
  414. * [group] Optional parameter pertaining to a Zp subgroup. If
  415. * this option is provided, the modulus and order of the element
  416. * will be checked against those of the group.
  417. * @throws {TypeError}
  418. * If the value is not a valid ZpGroupElement object.
  419. */
  420. checkZpGroupElement: function(element, label, group) {
  421. this.checkIsObjectWithProperties(element, label);
  422. if (typeof group !== 'undefined') {
  423. var groupP = group.p;
  424. var groupQ = group.q;
  425. var elementP = element.p;
  426. if (!elementP.equals(groupP)) {
  427. throw new TypeError(
  428. 'Expected modulus p of ' + label +
  429. ' to equal modulus of Zp subgroup provided as input: ' + groupP +
  430. ' ; Found: ' + elementP);
  431. }
  432. var elementQ = element.q;
  433. if (!elementQ.equals(groupQ)) {
  434. throw new TypeError(
  435. 'Expected order q of ' + label +
  436. ' to equal order of Zp subgroup provided as input: ' + groupQ +
  437. ' ; Found: ' + elementQ);
  438. }
  439. }
  440. },
  441. /**
  442. * Checks the validity of an Exponent object.
  443. *
  444. * @function checkExponent
  445. * @private
  446. * @param {Exponent}
  447. * exponent The exponent to check.
  448. * @param {string}
  449. * label The error message label for the object.
  450. * @param {Zpsubgroup}
  451. * [q] Optional parameter pertaining to a Zp subgroup order. If
  452. * this option is provided, the order of the exponent will be
  453. * checked against that order.
  454. * @throws {TypeError}
  455. * If the value is not a valid Exponent value.
  456. */
  457. checkExponent: function(exponent, label, q) {
  458. this.checkIsObjectWithProperties(exponent, label);
  459. if (typeof q !== 'undefined') {
  460. var exponentQ = exponent.q;
  461. if (!exponentQ.equals(q)) {
  462. throw new TypeError(
  463. 'Expected order q of ' + label +
  464. ' to equal order of Zp subgroup provided as input: ' + q +
  465. ' ; Found: ' + exponentQ);
  466. }
  467. }
  468. },
  469. /**
  470. * Checks the validity of an array of ZpGroupElement objects.
  471. *
  472. * @function checkZpGroupElements
  473. * @private
  474. * @param {ZpGroupElement[]}
  475. * elements The array to check.
  476. * @param {string}
  477. * label The error message label for the array.
  478. * @param {Zpsubgroup}
  479. * [group] Optional parameter pertaining to a Zp subgroup. If
  480. * this option is provided, the modulus and order of each element
  481. * will be checked against those of the group.
  482. * @throws {TypeError}
  483. * If the array of ZpGroupElement objects is not valid.
  484. */
  485. checkZpGroupElements: function(elements, label, group) {
  486. this.checkIsNonEmptyArray(elements, label);
  487. for (var i = 0; i < elements.length; i++) {
  488. this.checkZpGroupElement(
  489. elements[i], 'element ' + i + ' of ' + label, group);
  490. }
  491. },
  492. /**
  493. * Checks the validity of an array of Exponent objects.
  494. *
  495. * @function checkExponents
  496. * @private
  497. * @param {Exponent[]}
  498. * exponents The array to check.
  499. * @param {string}
  500. * label The error message label for the array.
  501. * @param {Zpsubgroup}
  502. * [q] Optional parameter pertaining to a Zp subgroup order. If
  503. * this option is provided, the order of the exponent will be
  504. * checked against that order.
  505. * @throws {TypeError}
  506. * If the array of Exponent objects is not valid.
  507. */
  508. checkExponents: function(exponents, label, q) {
  509. this.checkIsNonEmptyArray(exponents, label);
  510. for (var i = 0; i < exponents.length; i++) {
  511. this.checkExponent(exponents[i], 'exponent ' + i + ' of ' + label, q);
  512. }
  513. }
  514. };