generator.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 DigitalEnvelope = require('./envelope');
  11. var EncryptedSecretKeyPair = require('./encrypted-secret-keypair');
  12. var cryptoPolicy = require('scytl-cryptopolicy');
  13. var asymmetric = require('scytl-asymmetric');
  14. var symmetric = require('scytl-symmetric');
  15. var validator = require('./input-validator');
  16. var bitwise = require('scytl-bitwise');
  17. var codec = require('scytl-codec');
  18. module.exports = DigitalEnvelopeGenerator;
  19. /**
  20. * @class DigitalEnvelopeGenerator
  21. * @classdesc The digital envelope generator API. To instantiate this object,
  22. * use the method {@link DigitalEnvelopeService.newGenerator}.
  23. * @hideconstructor
  24. * @param {Object}
  25. * [options] An object containing optional arguments.
  26. * @param {Policy}
  27. * [options.policy=Default policy] The cryptographic policy to use.
  28. * @param {SymmetricCryptographyService}
  29. * [options.symmetricCryptographyService=Created internally] The
  30. * symmetric cryptography service to use.
  31. * @param {AsymmetricCryptographyService}
  32. * [options.asymmetricCryptographyService=Created internally] The
  33. * asymmetric cryptography service to use.
  34. */
  35. function DigitalEnvelopeGenerator(options) {
  36. options = options || {};
  37. var policy = cryptoPolicy.newInstance();
  38. if (options.policy) {
  39. policy.symmetric = options.policy.digitalEnvelope.symmetric;
  40. policy.asymmetric.cipher = options.policy.digitalEnvelope.asymmetric.cipher;
  41. }
  42. var symmetricService;
  43. if (options.symmetricCryptographyService) {
  44. symmetricService = options.symmetricCryptographyService;
  45. } else {
  46. symmetricService = symmetric.newService({policy: policy});
  47. }
  48. var asymmetricService;
  49. if (options.asymmetricCryptographyService) {
  50. asymmetricService = options.asymmetricCryptographyService;
  51. } else {
  52. asymmetricService = asymmetric.newService({policy: policy});
  53. }
  54. var secretKeyGenerator_ = symmetricService.newKeyGenerator();
  55. var symmetricCipher_ = symmetricService.newCipher();
  56. var macHandler_ = symmetricService.newMacHandler();
  57. var asymmetricEncrypter_ = asymmetricService.newEncrypter();
  58. var publicKeys_;
  59. /**
  60. * Initializes the Digital envelope generator with one or more public keys.
  61. *
  62. * @function init
  63. * @memberof DigitalEnvelopeGenerator
  64. * @param {...string}
  65. * arguments A comma separated list of the public keys, each in
  66. * PEM format.
  67. * @returns {DigitalEnvelopeGenerator} A reference to this object, to
  68. * facilitate method chaining.
  69. * @throws {Error}
  70. * If the input data validation fails.
  71. */
  72. this.init = function() {
  73. publicKeys_ = Array.prototype.slice.call(arguments);
  74. validator.checkIsNonEmptyStringArray(
  75. publicKeys_,
  76. 'public keys (PEM encoded) to initialize digital envelope generator');
  77. return this;
  78. };
  79. /**
  80. * Generates a digital envelope, given the data to store in the envelope.
  81. * The envelope can be generated with one or more public keys, each of whose
  82. * corresponding private key can be used to open the envelope. Before using
  83. * this method, the generator must have been initialized with at least one
  84. * public key, via the method {@link DigitalEnvelopeGenerator.init}.
  85. *
  86. * @function generate
  87. * @memberof DigitalEnvelopeGenerator
  88. * @param {Uint8Array|
  89. * string} data The data to store in the digital envelope. Data
  90. * of type <code>string</code> will be UTF-8 encoded.
  91. * @returns {DigitalEnvelope} The generated digital envelope.
  92. * @throws {Error}
  93. * If the input data validation fails or the digital envelope
  94. * could not be generated.
  95. */
  96. this.generate = function(data) {
  97. if (typeof publicKeys_ === 'undefined') {
  98. throw new Error(
  99. 'Could not generate digital envelope; Envelope generator has not been initialized with any public key');
  100. }
  101. if (typeof data === 'string') {
  102. data = codec.utf8Encode(data);
  103. }
  104. validator.checkIsInstanceOf(
  105. data, Uint8Array, 'Uint8Array', 'Data to store in digital envelope');
  106. try {
  107. // Generate encryption secret key and use it to symmetrically encrypt
  108. // data.
  109. var encryptionSecretKey = secretKeyGenerator_.nextEncryptionKey();
  110. var encryptedData =
  111. symmetricCipher_.init(encryptionSecretKey).encrypt(data);
  112. // Generate MAC secret key and use it to generate MAC of symmetrically
  113. // encrypted data.
  114. var macSecretKey = secretKeyGenerator_.nextMacKey();
  115. var mac = macHandler_.init(macSecretKey).generate(encryptedData);
  116. // Construct bit-wise concatenation of encryption and MAC secret keys.
  117. var secretKeyPair =
  118. bitwise.concatenate(encryptionSecretKey, macSecretKey);
  119. // Generate list of asymmetric encryptions of the secret key
  120. // concatenation, each encryption created using a different one of the
  121. // public keys provided as input for the digital envelope generation.
  122. var encryptedSecretKeyPairs = [];
  123. for (var i = 0; i < publicKeys_.length; i++) {
  124. var publicKeyPem = publicKeys_[i];
  125. var encryptedSecretKeyPair =
  126. asymmetricEncrypter_.init(publicKeyPem).encrypt(secretKeyPair);
  127. encryptedSecretKeyPairs.push(
  128. new EncryptedSecretKeyPair(encryptedSecretKeyPair, publicKeyPem));
  129. }
  130. return new DigitalEnvelope(encryptedData, mac, encryptedSecretKeyPairs);
  131. } catch (error) {
  132. throw new Error('Digital envelope could not be generated. ' + error);
  133. }
  134. };
  135. }