Source: encrypt/algo/encryptor.js

  1. /**
  2. * Copyright (C) 2015-2016 Regents of the University of California.
  3. * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  4. * @author: From ndn-group-encrypt src/encryptor https://github.com/named-data/ndn-group-encrypt
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. * A copy of the GNU Lesser General Public License is in the file COPYING.
  19. */
  20. /** @ignore */
  21. var Crypto = require('../../crypto.js'); /** @ignore */
  22. var Name = require('../../name.js').Name; /** @ignore */
  23. var KeyLocator = require('../../key-locator.js').KeyLocator; /** @ignore */
  24. var KeyLocatorType = require('../../key-locator.js').KeyLocatorType; /** @ignore */
  25. var TlvWireFormat = require('../../encoding/tlv-wire-format.js').TlvWireFormat; /** @ignore */
  26. var Blob = require('../../util/blob.js').Blob; /** @ignore */
  27. var AesAlgorithm = require('./aes-algorithm.js').AesAlgorithm; /** @ignore */
  28. var RsaAlgorithm = require('./rsa-algorithm.js').RsaAlgorithm; /** @ignore */
  29. var EncryptParams = require('./encrypt-params.js').EncryptParams; /** @ignore */
  30. var EncryptAlgorithmType = require('./encrypt-params.js').EncryptAlgorithmType; /** @ignore */
  31. var EncryptedContent = require('../encrypted-content.js').EncryptedContent; /** @ignore */
  32. var SyncPromise = require('../../util/sync-promise.js').SyncPromise;
  33. /**
  34. * Encryptor has static constants and utility methods for encryption, such as
  35. * encryptData.
  36. * @constructor
  37. */
  38. var Encryptor = function Encryptor(value)
  39. {
  40. };
  41. exports.Encryptor = Encryptor;
  42. Encryptor.NAME_COMPONENT_FOR = new Name.Component("FOR");
  43. Encryptor.NAME_COMPONENT_READ = new Name.Component("READ");
  44. Encryptor.NAME_COMPONENT_SAMPLE = new Name.Component("SAMPLE");
  45. Encryptor.NAME_COMPONENT_ACCESS = new Name.Component("ACCESS");
  46. Encryptor.NAME_COMPONENT_E_KEY = new Name.Component("E-KEY");
  47. Encryptor.NAME_COMPONENT_D_KEY = new Name.Component("D-KEY");
  48. Encryptor.NAME_COMPONENT_C_KEY = new Name.Component("C-KEY");
  49. /**
  50. * Prepare an encrypted data packet by encrypting the payload using the key
  51. * according to the params. In addition, this prepares the encoded
  52. * EncryptedContent with the encryption result using keyName and params. The
  53. * encoding is set as the content of the data packet. If params defines an
  54. * asymmetric encryption algorithm and the payload is larger than the maximum
  55. * plaintext size, this encrypts the payload with a symmetric key that is
  56. * asymmetrically encrypted and provided as a nonce in the content of the data
  57. * packet. The packet's /<dataName>/ is updated to be <dataName>/FOR/<keyName>.
  58. * @param {Data} data The data packet which is updated.
  59. * @param {Blob} payload The payload to encrypt.
  60. * @param {Name} keyName The key name for the EncryptedContent.
  61. * @param {Blob} key The encryption key value.
  62. * @param {EncryptParams} params The parameters for encryption.
  63. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  64. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  65. * an async Promise.
  66. * @return {Promise|SyncPromise} A promise which fulfills when the data packet
  67. * is updated.
  68. */
  69. Encryptor.encryptDataPromise = function
  70. (data, payload, keyName, key, params, useSync)
  71. {
  72. var dataName = data.getName();
  73. dataName.append(Encryptor.NAME_COMPONENT_FOR).append(keyName);
  74. data.setName(dataName);
  75. var algorithmType = params.getAlgorithmType();
  76. if (algorithmType == EncryptAlgorithmType.AesCbc ||
  77. algorithmType == EncryptAlgorithmType.AesEcb) {
  78. return Encryptor.encryptSymmetricPromise_
  79. (payload, key, keyName, params, useSync)
  80. .then(function(content) {
  81. data.setContent(content.wireEncode(TlvWireFormat.get()));
  82. return SyncPromise.resolve();
  83. });
  84. }
  85. else if (algorithmType == EncryptAlgorithmType.RsaPkcs ||
  86. algorithmType == EncryptAlgorithmType.RsaOaep) {
  87. // Node.js doesn't have a direct way to get the maximum plain text size, so
  88. // try to encrypt the payload first and catch the error if it is too big.
  89. return Encryptor.encryptAsymmetricPromise_
  90. (payload, key, keyName, params, useSync)
  91. .then(function(content) {
  92. data.setContent(content.wireEncode(TlvWireFormat.get()));
  93. return SyncPromise.resolve();
  94. }, function(err) {
  95. if (err.message.indexOf("data too large for key size") < 0)
  96. // Not the expected error.
  97. throw err;
  98. // The payload is larger than the maximum plaintext size.
  99. // 128-bit nonce.
  100. var nonceKeyBuffer = Crypto.randomBytes(16);
  101. var nonceKey = new Blob(nonceKeyBuffer, false);
  102. var nonceKeyName = new Name(keyName);
  103. nonceKeyName.append("nonce");
  104. var symmetricParams = new EncryptParams
  105. (EncryptAlgorithmType.AesCbc, AesAlgorithm.BLOCK_SIZE);
  106. var nonceContent;
  107. return Encryptor.encryptSymmetricPromise_
  108. (payload, nonceKey, nonceKeyName, symmetricParams, useSync)
  109. .then(function(localNonceContent) {
  110. nonceContent = localNonceContent;
  111. return Encryptor.encryptAsymmetricPromise_
  112. (nonceKey, key, keyName, params, useSync);
  113. })
  114. .then(function(payloadContent) {
  115. var nonceContentEncoding = nonceContent.wireEncode();
  116. var payloadContentEncoding = payloadContent.wireEncode();
  117. var content = new Buffer
  118. (nonceContentEncoding.size() + payloadContentEncoding.size());
  119. payloadContentEncoding.buf().copy(content, 0);
  120. nonceContentEncoding.buf().copy(content, payloadContentEncoding.size());
  121. data.setContent(new Blob(content, false));
  122. return SyncPromise.resolve();
  123. });
  124. });
  125. }
  126. else
  127. return SyncPromise.reject(new Error("Unsupported encryption method"));
  128. };
  129. /**
  130. * Prepare an encrypted data packet by encrypting the payload using the key
  131. * according to the params. In addition, this prepares the encoded
  132. * EncryptedContent with the encryption result using keyName and params. The
  133. * encoding is set as the content of the data packet. If params defines an
  134. * asymmetric encryption algorithm and the payload is larger than the maximum
  135. * plaintext size, this encrypts the payload with a symmetric key that is
  136. * asymmetrically encrypted and provided as a nonce in the content of the data
  137. * packet.
  138. * @param {Data} data The data packet which is updated.
  139. * @param {Blob} payload The payload to encrypt.
  140. * @param {Name} keyName The key name for the EncryptedContent.
  141. * @param {Blob} key The encryption key value.
  142. * @param {EncryptParams} params The parameters for encryption.
  143. * @throws Error If encryptPromise doesn't return a SyncPromise which is
  144. * already fulfilled.
  145. */
  146. Encryptor.encryptData = function(data, payload, keyName, key, params)
  147. {
  148. return SyncPromise.getValue(Encryptor.encryptDataPromise
  149. (data, payload, keyName, key, params, true));
  150. };
  151. /**
  152. * Encrypt the payload using the symmetric key according to params, and return
  153. * an EncryptedContent.
  154. * @param {Blob} payload The data to encrypt.
  155. * @param {Blob} key The key value.
  156. * @param {Name} keyName The key name for the EncryptedContent key locator.
  157. * @param {EncryptParams} params The parameters for encryption.
  158. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  159. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  160. * an async Promise.
  161. * @return {Promise|SyncPromise} A promise which returns a new EncryptedContent.
  162. */
  163. Encryptor.encryptSymmetricPromise_ = function
  164. (payload, key, keyName, params, useSync)
  165. {
  166. var algorithmType = params.getAlgorithmType();
  167. var initialVector = params.getInitialVector();
  168. var keyLocator = new KeyLocator();
  169. keyLocator.setType(KeyLocatorType.KEYNAME);
  170. keyLocator.setKeyName(keyName);
  171. if (algorithmType == EncryptAlgorithmType.AesCbc ||
  172. algorithmType == EncryptAlgorithmType.AesEcb) {
  173. if (algorithmType == EncryptAlgorithmType.AesCbc) {
  174. if (initialVector.size() != AesAlgorithm.BLOCK_SIZE)
  175. return SyncPromise.reject(new Error("incorrect initial vector size"));
  176. }
  177. return AesAlgorithm.encryptPromise(key, payload, params, useSync)
  178. .then(function(encryptedPayload) {
  179. var result = new EncryptedContent();
  180. result.setAlgorithmType(algorithmType);
  181. result.setKeyLocator(keyLocator);
  182. result.setPayload(encryptedPayload);
  183. result.setInitialVector(initialVector);
  184. return SyncPromise.resolve(result);
  185. });
  186. }
  187. else
  188. return SyncPromise.reject(new Error("Unsupported encryption method"));
  189. };
  190. /**
  191. * Encrypt the payload using the asymmetric key according to params, and
  192. * return an EncryptedContent.
  193. * @param {Blob} payload The data to encrypt. The size should be within range of
  194. * the key.
  195. * @param {Blob} key The key value.
  196. * @param {Name} keyName The key name for the EncryptedContent key locator.
  197. * @param {EncryptParams} params The parameters for encryption.
  198. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  199. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  200. * an async Promise.
  201. * @return {Promise|SyncPromise} A promise which returns a new EncryptedContent.
  202. */
  203. Encryptor.encryptAsymmetricPromise_ = function
  204. (payload, key, keyName, params, useSync)
  205. {
  206. var algorithmType = params.getAlgorithmType();
  207. var keyLocator = new KeyLocator();
  208. keyLocator.setType(KeyLocatorType.KEYNAME);
  209. keyLocator.setKeyName(keyName);
  210. if (algorithmType == EncryptAlgorithmType.RsaPkcs ||
  211. algorithmType == EncryptAlgorithmType.RsaOaep) {
  212. return RsaAlgorithm.encryptPromise(key, payload, params, useSync)
  213. .then(function(encryptedPayload) {
  214. var result = new EncryptedContent();
  215. result.setAlgorithmType(algorithmType);
  216. result.setKeyLocator(keyLocator);
  217. result.setPayload(encryptedPayload);
  218. return SyncPromise.resolve(result);
  219. });
  220. }
  221. else
  222. return SyncPromise.reject(new Error("Unsupported encryption method"));
  223. };