2
0

index.spec.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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, mocha:true */
  9. 'use strict';
  10. var cryptoPolicy = require('scytl-cryptopolicy');
  11. var asymmetric = require('../lib/index');
  12. var constants = require('../lib/constants');
  13. var bitwise = require('scytl-bitwise');
  14. var codec = require('scytl-codec');
  15. var forge = require('node-forge');
  16. describe('The asymmetric cryptography module should be able to ...', function() {
  17. var DATA = 'anystring';
  18. var OTHER_DATA_1 = DATA + 'a';
  19. var OTHER_DATA_2 = DATA + 'b';
  20. var PUBLIC_KEY_PEM =
  21. '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAglypZU45bnf2opnRI+Y51VqouBpvDT33xIB/OtbwKzwVpi+JrjBFtfk33tE9t/dSRs79CK94HRhCWcOiLa2qWPrjeZ9SBiEyScrhIvRZVBF41zBgwQNuRvJCsKmAqlZaFNJDZxEP4repmlBn1CfVFmfrXmOKqwP5F7l9ZtucveRzsfmF1yVPFkW8TMuB3YqMiyymyqHlS8ujCsu5I8tpgPbwuxdMOY94fNhSXrYkY8IuX1g1zdq/Z1jluOaR/UqK4UpnbuJaH/F0VgDNiWh6cTD0DFGEk0b70i5wU4Q3L/S6XZQRvSuADoCbhwBKuFL5pW5n865oLVb5S3wuVdWaGwIDAQAB-----END PUBLIC KEY-----';
  22. var PRIVATE_KEY_PEM =
  23. '-----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEAglypZU45bnf2opnRI+Y51VqouBpvDT33xIB/OtbwKzwVpi+JrjBFtfk33tE9t/dSRs79CK94HRhCWcOiLa2qWPrjeZ9SBiEyScrhIvRZVBF41zBgwQNuRvJCsKmAqlZaFNJDZxEP4repmlBn1CfVFmfrXmOKqwP5F7l9ZtucveRzsfmF1yVPFkW8TMuB3YqMiyymyqHlS8ujCsu5I8tpgPbwuxdMOY94fNhSXrYkY8IuX1g1zdq/Z1jluOaR/UqK4UpnbuJaH/F0VgDNiWh6cTD0DFGEk0b70i5wU4Q3L/S6XZQRvSuADoCbhwBKuFL5pW5n865oLVb5S3wuVdWaGwIDAQABAoIBAC/tn34Wf3kE9BGeGc1oFLVDaqqdVVz5/oEpeR2J7q0GnzMFYUpAhzC7WvY52cYsUPyll1Q9Jx0TUTmteo/uvKWQQFfz4nVMeS+2PoXabolBDzuWlsv/1eiRo0FOYHa/3siu8YcQN9X0DpAkpbfTmT1uoZOHZ3EuucMmOFu7vGn38Grw8bSxpR0uvTtnb8ygC+aB51y38RMyhzQQanrM8FMeAfDAy6IB0Yo7b0c50Cxa6Ax4nqn9LXyGakr5WeAMkgTIOA/GId9SZD4e5eRpq+628pOeR4O9datFltgl6r1+A4ii2VrJsDqeatGtODlX6KRKqwFHoGIa2TjgSZLuorECgYEAxeSZDOOgFsI5mB7RkRzZaQ9znJ15sgdyZiAFZAOUah4hSGdAXNAnZTlrdacduXEu3EfkpuPToX7xZSv5FRYwfBwMwCLeytlGLPjQzWejZGbo4+KqgzWb9fECDYVtDPlJ/+yLih9nt67BHweJKxYydl18rVigdVyy22X86NijSykCgYEAqKPUrXZAo+TJvmTw4tgsibJgvXBYBhmsej8mGNQw+Nyp2gV28sgm61ifIeXKS8teq+MFwGA6cHQedbsCqhMHokdhESZmlbWxhSFLihQcewBxwvrBwbaxI23yXRzwMewznZFL032PpcbqrmwFmcSSEZ3nmbvTH6ShqLW+pzDNp6MCgYBQLzdgxJ7qedqSa/JohTMG4e7rh9d2rpPJE7J7ewPZF8pOpx+qO+Gqn2COdJ+Ts2vUcAETKn9nEaPIZc/wnmQY9dioxbhWo0FPGaaphBPtq9Ez/XUv4zoFppk5V1X/isdUPsmvttf00oeIBiqrXbwmv+yz5JRn2Z7TTXjz9Ev+OQKBgQCUuoCMRzl1EgcXIqEL/0kwW6BUEqufHa9u1Ri9Vw6lvL8T6DPipMEmWK9nzuid9gtVns/ovTVtDgv7GuabplLaPQePf4WDzY11c0rSyS/hDyBFrK+LL5uEOqhAlJAGB2HyOj1clWVF+GvrTpuV5LZKUS/79pmZU7G7QCaX/0Ow7wKBgC/kDH7cmWQnWvvJ5izrx/7PogQVPOLELeUIGLu/hjsSdDKiFCxCUZ948+9NuG+DnpXDWzw//r8mPBRRGGsqFws5Aipp7yjQ3kRDCCzGelPCVhHyfmKqA+8ewXPulKS3/wIyHIvaXmsuAtTfurHtpRyzjKmCBK1Y6WQ3trIXvo7s-----END RSA PRIVATE KEY-----';
  24. var data_;
  25. var otherData1_;
  26. var otherData2_;
  27. var dataParts_;
  28. var service_;
  29. var signer_;
  30. var sigVerifier_;
  31. var encrypter_;
  32. var decrypter_;
  33. var signature_;
  34. var encryptedData_;
  35. beforeAll(function() {
  36. data_ = codec.utf8Encode(DATA);
  37. otherData1_ = codec.utf8Encode(OTHER_DATA_1);
  38. otherData2_ = codec.utf8Encode(OTHER_DATA_2);
  39. dataParts_ = [data_, otherData1_, otherData2_];
  40. service_ = asymmetric.newService();
  41. signer_ = service_.newSigner().init(PRIVATE_KEY_PEM);
  42. sigVerifier_ = service_.newSignatureVerifier().init(PUBLIC_KEY_PEM);
  43. encrypter_ = service_.newEncrypter().init(PUBLIC_KEY_PEM);
  44. decrypter_ = service_.newDecrypter().init(PRIVATE_KEY_PEM);
  45. signature_ = signer_.sign(data_);
  46. encryptedData_ = encrypter_.encrypt(data_);
  47. });
  48. describe('create an asymmetric cryptography service that should be able to ..', function() {
  49. it('create a new RsaPublicKey object', function() {
  50. var rsaPublicKey1 = service_.newRsaPublicKey({pem: PUBLIC_KEY_PEM});
  51. var rsaPublicKey2 =
  52. service_.newRsaPublicKey({n: rsaPublicKey1.n, e: rsaPublicKey1.e});
  53. expect(rsaPublicKey2.n).toEqual(rsaPublicKey1.n);
  54. expect(rsaPublicKey2.e).toEqual(rsaPublicKey1.e);
  55. var rsaPublicKey1Pem = rsaPublicKey1.toPem();
  56. var offset = rsaPublicKey1Pem.indexOf('\n') + 1;
  57. expect(rsaPublicKey1Pem.indexOf('\n', offset))
  58. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  59. var rsaPublicKey2Pem = rsaPublicKey1.toPem();
  60. offset = rsaPublicKey2Pem.indexOf('\n') + 1;
  61. expect(rsaPublicKey2Pem.indexOf('\n', offset))
  62. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  63. expect(removeNewLineChars(rsaPublicKey1Pem))
  64. .toBe(removeNewLineChars(PUBLIC_KEY_PEM));
  65. expect(removeNewLineChars(rsaPublicKey2Pem))
  66. .toBe(removeNewLineChars(PUBLIC_KEY_PEM));
  67. });
  68. it('create a new RsaPrivateKey object', function() {
  69. var rsaPrivateKey1 = service_.newRsaPrivateKey({pem: PRIVATE_KEY_PEM});
  70. var params = {
  71. n: rsaPrivateKey1.n,
  72. e: rsaPrivateKey1.e,
  73. d: rsaPrivateKey1.d,
  74. p: rsaPrivateKey1.p,
  75. q: rsaPrivateKey1.q,
  76. dP: rsaPrivateKey1.dP,
  77. dQ: rsaPrivateKey1.dQ,
  78. qInv: rsaPrivateKey1.qInv
  79. };
  80. var rsaPrivateKey2 = service_.newRsaPrivateKey(params);
  81. expect(rsaPrivateKey2.n).toEqual(rsaPrivateKey1.n);
  82. expect(rsaPrivateKey2.e).toEqual(rsaPrivateKey1.e);
  83. expect(rsaPrivateKey2.d).toEqual(rsaPrivateKey1.d);
  84. expect(rsaPrivateKey2.p).toEqual(rsaPrivateKey1.p);
  85. expect(rsaPrivateKey2.q).toEqual(rsaPrivateKey1.q);
  86. expect(rsaPrivateKey2.dP).toEqual(rsaPrivateKey1.dP);
  87. expect(rsaPrivateKey2.dQ).toEqual(rsaPrivateKey1.dQ);
  88. expect(rsaPrivateKey2.qInv).toEqual(rsaPrivateKey1.qInv);
  89. var rsaPrivateKey1Pem = rsaPrivateKey1.toPem();
  90. var offset = rsaPrivateKey1Pem.indexOf('\n') + 1;
  91. expect(rsaPrivateKey1Pem.indexOf('\n', offset))
  92. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  93. var rsaPrivateKey2Pem = rsaPrivateKey2.toPem();
  94. offset = rsaPrivateKey2Pem.indexOf('\n') + 1;
  95. expect(rsaPrivateKey2Pem.indexOf('\n', offset))
  96. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  97. expect(removeNewLineChars(rsaPrivateKey1Pem))
  98. .toBe(removeNewLineChars(PRIVATE_KEY_PEM));
  99. expect(removeNewLineChars(rsaPrivateKey2Pem))
  100. .toBe(removeNewLineChars(PRIVATE_KEY_PEM));
  101. });
  102. it('create a new KeyPair object', function() {
  103. var keyPair = service_.newKeyPair(PUBLIC_KEY_PEM, PRIVATE_KEY_PEM);
  104. expect(removeNewLineChars(keyPair.publicKey))
  105. .toBe(removeNewLineChars(PUBLIC_KEY_PEM));
  106. expect(removeNewLineChars(keyPair.privateKey))
  107. .toBe(removeNewLineChars(PRIVATE_KEY_PEM));
  108. });
  109. describe(
  110. 'create a key pair generator that should be able to ..', function() {
  111. it('generate a new key pair', function() {
  112. // Note: Key size here is set to value lower than that allowed by
  113. // policy to keep test time reasonable.
  114. var policy = cryptoPolicy.newInstance();
  115. policy.asymmetric.keyPair.encryption.keyLengthBits = 128;
  116. var service = asymmetric.newService({policy: policy});
  117. var keyPairGenerator = service.newKeyPairGenerator();
  118. var keyPair = keyPairGenerator.next();
  119. var publicKey = keyPair.publicKey;
  120. var privateKey = keyPair.privateKey;
  121. expect(publicKey).toBeDefined();
  122. expect(publicKey).toMatch(/^-----BEGIN PUBLIC/);
  123. expect(privateKey).toBeDefined();
  124. expect(privateKey).toMatch(/^-----BEGIN RSA PRIVATE/);
  125. var modulus = forge.pki.publicKeyFromPem(publicKey).n;
  126. var keyLengthBits = modulus.toString(2).length;
  127. expect(keyLengthBits)
  128. .toBe(policy.asymmetric.keyPair.encryption.keyLengthBits);
  129. });
  130. });
  131. describe('create a signer/signature verifier pair that should be able to ..', function() {
  132. it('sign some data and verify the signature', function() {
  133. var signature = signer_.sign(data_);
  134. expect(sigVerifier_.verify(signature, data_)).toBeTruthy();
  135. });
  136. it('sign some data consisting of multiple parts', function() {
  137. // Call sign with no arguments.
  138. for (var i = 0; i < dataParts_.length; i++) {
  139. signer_.update(dataParts_[i]);
  140. }
  141. var signature = signer_.sign();
  142. var verified = sigVerifier_.verify(
  143. signature, bitwise.concatenate(data_, otherData1_, otherData2_));
  144. expect(verified).toBeTruthy();
  145. // Call sign with argument consisting of last data part.
  146. for (var j = 0; j < (dataParts_.length - 1); j++) {
  147. signer_.update(dataParts_[j]);
  148. }
  149. signature = signer_.sign(otherData2_);
  150. verified = sigVerifier_.verify(
  151. signature, bitwise.concatenate(data_, otherData1_, otherData2_));
  152. expect(verified).toBeTruthy();
  153. });
  154. it('sign some data consisting of multiple parts, using method chaining',
  155. function() {
  156. // Call sign with no arguments.
  157. var signature = signer_.update(data_)
  158. .update(otherData1_)
  159. .update(otherData2_)
  160. .sign();
  161. var verified = sigVerifier_.verify(
  162. signature, bitwise.concatenate(data_, otherData1_, otherData2_));
  163. expect(verified).toBeTruthy();
  164. // Call sign with argument consisting of last data part.
  165. signature =
  166. signer_.update(data_).update(otherData1_).sign(otherData2_);
  167. verified = sigVerifier_.verify(
  168. signature, bitwise.concatenate(data_, otherData1_, otherData2_));
  169. expect(verified).toBeTruthy();
  170. });
  171. it('verify a signature of data consisting of multiple parts', function() {
  172. var signature =
  173. signer_.sign(bitwise.concatenate(data_, otherData1_, otherData2_));
  174. // Call verify with no arguments.
  175. for (var i = 0; i < dataParts_.length; i++) {
  176. sigVerifier_.update(dataParts_[i]);
  177. }
  178. var verified = sigVerifier_.verify(signature);
  179. expect(verified).toBeTruthy();
  180. // Call verify with argument consisting of last data part.
  181. for (var j = 0; j < (dataParts_.length - 1); j++) {
  182. sigVerifier_.update(dataParts_[j]);
  183. }
  184. verified = sigVerifier_.verify(signature, otherData2_);
  185. expect(verified).toBeTruthy();
  186. });
  187. it('verify a signature of data consisting of multiple parts, using method chaining',
  188. function() {
  189. var signature = signer_.sign(
  190. bitwise.concatenate(data_, otherData1_, otherData2_));
  191. // Calli verify with no arguments.
  192. var verified = sigVerifier_.update(data_)
  193. .update(otherData1_)
  194. .update(otherData2_)
  195. .verify(signature);
  196. expect(verified).toBeTruthy();
  197. // Call verify with argument consisting of last data part.
  198. verified = sigVerifier_.update(data_)
  199. .update(otherData1_)
  200. .verify(signature, otherData2_);
  201. expect(verified).toBeTruthy();
  202. });
  203. it('sign some data of type string and verify the signature', function() {
  204. var signature =
  205. signer_.update(DATA).update(OTHER_DATA_1).sign(OTHER_DATA_2);
  206. var verified = sigVerifier_.update(DATA)
  207. .update(OTHER_DATA_1)
  208. .verify(signature, OTHER_DATA_2);
  209. expect(verified).toBeTruthy();
  210. });
  211. it('sign some data and verify the signature, using RsaPrivateKey and RsaPublicKey objects',
  212. function() {
  213. var rsaPrivateKey =
  214. new service_.newRsaPrivateKey({pem: PRIVATE_KEY_PEM});
  215. var signer = service_.newSigner().init(rsaPrivateKey.toPem());
  216. var rsaPublicKey =
  217. new service_.newRsaPublicKey({pem: PUBLIC_KEY_PEM});
  218. var sigVerifier =
  219. service_.newSignatureVerifier().init(rsaPublicKey.toPem());
  220. var signature = signer.sign(data_);
  221. expect(sigVerifier.verify(signature, data_)).toBeTruthy();
  222. });
  223. it('throw an error when updating the signer with some data before the signer has been initialized with a private key',
  224. function() {
  225. var signer = service_.newSigner();
  226. expect(function() {
  227. signer.update(data_);
  228. }).toThrow();
  229. });
  230. it('throw an error when signing some data before the signer has been initialized with a private key',
  231. function() {
  232. var signer = service_.newSigner();
  233. expect(function() {
  234. signer.sign(data_);
  235. }).toThrow();
  236. });
  237. it('throw an error when updating the signature verifier with some data before the verifier has been initialized with a public key',
  238. function() {
  239. var sigVerifier = service_.newSignatureVerifier();
  240. expect(function() {
  241. sigVerifier.update(data_);
  242. }).toThrow();
  243. });
  244. it('throw an error when verifying a signature before the signature verifier has been initialized with a public key',
  245. function() {
  246. var sigVerifier = service_.newSignatureVerifier();
  247. expect(function() {
  248. sigVerifier.verify(signature_, data_);
  249. }).toThrow();
  250. });
  251. it('throw an error when signing without either providing data or having previously updated the signer with some data',
  252. function() {
  253. var signer = service_.newSigner().init(PRIVATE_KEY_PEM);
  254. expect(function() {
  255. signer.sign();
  256. }).toThrow();
  257. });
  258. it('throw an error when verifying a signature without either providing data or having previously updated the verifier with some data',
  259. function() {
  260. var sigVerifier =
  261. service_.newSignatureVerifier().init(PUBLIC_KEY_PEM);
  262. expect(function() {
  263. sigVerifier.verify(signature_);
  264. }).toThrow();
  265. });
  266. });
  267. describe(
  268. 'create an encrypter/decrypter pair that should be able to ..',
  269. function() {
  270. it('encrypt and decrypt some data', function() {
  271. var encryptedData = encrypter_.encrypt(data_);
  272. var decryptedData = decrypter_.decrypt(encryptedData);
  273. expect(decryptedData).toEqual(data_);
  274. });
  275. it('encrypt and decrypt some data of type string', function() {
  276. var encryptedData = encrypter_.encrypt(DATA);
  277. var decryptedData =
  278. codec.utf8Decode(decrypter_.decrypt(encryptedData));
  279. expect(decryptedData).toBe(DATA);
  280. });
  281. it('encrypt and decrypt some data, using RsaPublicKey and RsaPrivateKey objects',
  282. function() {
  283. var rsaPublicKey =
  284. new service_.newRsaPublicKey({pem: PUBLIC_KEY_PEM});
  285. var encrypter =
  286. service_.newEncrypter().init(rsaPublicKey.toPem());
  287. var rsaPrivateKey =
  288. new service_.newRsaPrivateKey({pem: PRIVATE_KEY_PEM});
  289. var decrypter =
  290. service_.newDecrypter().init(rsaPrivateKey.toPem());
  291. var encryptedData = encrypter.encrypt(DATA);
  292. var decryptedData =
  293. codec.utf8Decode(decrypter.decrypt(encryptedData));
  294. expect(decryptedData).toBe(DATA);
  295. });
  296. it('throw an error when encrypting some data before the encrypter has been initialized with a public key',
  297. function() {
  298. var encrypter = service_.newEncrypter();
  299. expect(function() {
  300. encrypter.encrypt(data_);
  301. }).toThrow();
  302. });
  303. it('throw an error when decrypting before the decrypter has been initialized with a private key',
  304. function() {
  305. var decrypter = service_.newDecrypter();
  306. expect(function() {
  307. decrypter.decrypt(encryptedData_);
  308. }).toThrow();
  309. });
  310. });
  311. });
  312. });
  313. function removeNewLineChars(str) {
  314. return str.replace(/(\r\n|\n|\r)/gm, '');
  315. }