BlockModes.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*!
  2. * Crypto-JS contribution from Simon Greatrix
  3. */
  4. (function () {
  5. var C = typeof window === 'undefined' ? require('./Crypto').Crypto : window.Crypto;
  6. // Create pad namespace
  7. var C_pad = (C.pad = {});
  8. // Calculate the number of padding bytes required.
  9. function _requiredPadding(cipher, message) {
  10. var blockSizeInBytes = cipher._blocksize * 4;
  11. var reqd = blockSizeInBytes - (message.length % blockSizeInBytes);
  12. return reqd;
  13. }
  14. // Remove padding when the final byte gives the number of padding bytes.
  15. var _unpadLength = function (message) {
  16. var pad = message.pop();
  17. for (var i = 1; i < pad; i++) {
  18. message.pop();
  19. }
  20. };
  21. // No-operation padding, used for stream ciphers
  22. C_pad.NoPadding = {
  23. pad: function (cipher, message) {},
  24. unpad: function (message) {}
  25. };
  26. // Zero Padding.
  27. //
  28. // If the message is not an exact number of blocks, the final block is
  29. // completed with 0x00 bytes. There is no unpadding.
  30. C_pad.ZeroPadding = {
  31. pad: function (cipher, message) {
  32. var blockSizeInBytes = cipher._blocksize * 4;
  33. var reqd = message.length % blockSizeInBytes;
  34. if (reqd != 0) {
  35. for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) {
  36. message.push(0);
  37. }
  38. }
  39. },
  40. unpad: function (message) {}
  41. };
  42. // ISO/IEC 7816-4 padding.
  43. //
  44. // Pads the plain text with an 0x80 byte followed by as many 0x00
  45. // bytes are required to complete the block.
  46. C_pad.iso7816 = {
  47. pad: function (cipher, message) {
  48. var reqd = _requiredPadding(cipher, message);
  49. message.push(128);
  50. for (; reqd > 1; reqd--) {
  51. message.push(0);
  52. }
  53. },
  54. unpad: function (message) {
  55. while (message.pop() != 128) {}
  56. }
  57. };
  58. // ANSI X.923 padding
  59. //
  60. // The final block is padded with zeros except for the last byte of the
  61. // last block which contains the number of padding bytes.
  62. C_pad.ansix923 = {
  63. pad: function (cipher, message) {
  64. var reqd = _requiredPadding(cipher, message);
  65. for (var i = 1; i < reqd; i++) {
  66. message.push(0);
  67. }
  68. message.push(reqd);
  69. },
  70. unpad: _unpadLength
  71. };
  72. // ISO 10126
  73. //
  74. // The final block is padded with random bytes except for the last
  75. // byte of the last block which contains the number of padding bytes.
  76. C_pad.iso10126 = {
  77. pad: function (cipher, message) {
  78. var reqd = _requiredPadding(cipher, message);
  79. for (var i = 1; i < reqd; i++) {
  80. message.push(Math.floor(Math.random() * 256));
  81. }
  82. message.push(reqd);
  83. },
  84. unpad: _unpadLength
  85. };
  86. // PKCS7 padding
  87. //
  88. // PKCS7 is described in RFC 5652. Padding is in whole bytes. The
  89. // value of each added byte is the number of bytes that are added,
  90. // i.e. N bytes, each of value N are added.
  91. C_pad.pkcs7 = {
  92. pad: function (cipher, message) {
  93. var reqd = _requiredPadding(cipher, message);
  94. for (var i = 0; i < reqd; i++) {
  95. message.push(reqd);
  96. }
  97. },
  98. unpad: _unpadLength
  99. };
  100. // Create mode namespace
  101. var C_mode = (C.mode = {});
  102. /**
  103. * Mode base "class".
  104. */
  105. var Mode = (C_mode.Mode = function (padding) {
  106. if (padding) {
  107. this._padding = padding;
  108. }
  109. });
  110. Mode.prototype = {
  111. encrypt: function (cipher, m, iv) {
  112. this._padding.pad(cipher, m);
  113. this._doEncrypt(cipher, m, iv);
  114. },
  115. decrypt: function (cipher, m, iv) {
  116. this._doDecrypt(cipher, m, iv);
  117. this._padding.unpad(m);
  118. },
  119. // Default padding
  120. _padding: C_pad.iso7816
  121. };
  122. /**
  123. * Electronic Code Book mode.
  124. *
  125. * ECB applies the cipher directly against each block of the input.
  126. *
  127. * ECB does not require an initialization vector.
  128. */
  129. var ECB = (C_mode.ECB = function () {
  130. // Call parent constructor
  131. Mode.apply(this, arguments);
  132. });
  133. // Inherit from Mode
  134. var ECB_prototype = (ECB.prototype = new Mode());
  135. // Concrete steps for Mode template
  136. ECB_prototype._doEncrypt = function (cipher, m, iv) {
  137. var blockSizeInBytes = cipher._blocksize * 4;
  138. // Encrypt each block
  139. for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
  140. cipher._encryptblock(m, offset);
  141. }
  142. };
  143. ECB_prototype._doDecrypt = function (cipher, c, iv) {
  144. var blockSizeInBytes = cipher._blocksize * 4;
  145. // Decrypt each block
  146. for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
  147. cipher._decryptblock(c, offset);
  148. }
  149. };
  150. // ECB never uses an IV
  151. ECB_prototype.fixOptions = function (options) {
  152. options.iv = [];
  153. };
  154. /**
  155. * Cipher block chaining
  156. *
  157. * The first block is XORed with the IV. Subsequent blocks are XOR with the
  158. * previous cipher output.
  159. */
  160. var CBC = (C_mode.CBC = function () {
  161. // Call parent constructor
  162. Mode.apply(this, arguments);
  163. });
  164. // Inherit from Mode
  165. var CBC_prototype = (CBC.prototype = new Mode());
  166. // Concrete steps for Mode template
  167. CBC_prototype._doEncrypt = function (cipher, m, iv) {
  168. var blockSizeInBytes = cipher._blocksize * 4;
  169. // Encrypt each block
  170. for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
  171. if (offset == 0) {
  172. // XOR first block using IV
  173. for (var i = 0; i < blockSizeInBytes; i++) {
  174. m[i] ^= iv[i];
  175. }
  176. } else {
  177. // XOR this block using previous crypted block
  178. for (var i = 0; i < blockSizeInBytes; i++) {
  179. m[offset + i] ^= m[offset + i - blockSizeInBytes];
  180. }
  181. }
  182. // Encrypt block
  183. cipher._encryptblock(m, offset);
  184. }
  185. };
  186. CBC_prototype._doDecrypt = function (cipher, c, iv) {
  187. var blockSizeInBytes = cipher._blocksize * 4;
  188. // At the start, the previously crypted block is the IV
  189. var prevCryptedBlock = iv;
  190. // Decrypt each block
  191. for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
  192. // Save this crypted block
  193. var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
  194. // Decrypt block
  195. cipher._decryptblock(c, offset);
  196. // XOR decrypted block using previous crypted block
  197. for (var i = 0; i < blockSizeInBytes; i++) {
  198. c[offset + i] ^= prevCryptedBlock[i];
  199. }
  200. prevCryptedBlock = thisCryptedBlock;
  201. }
  202. };
  203. /**
  204. * Cipher feed back
  205. *
  206. * The cipher output is XORed with the plain text to produce the cipher output,
  207. * which is then fed back into the cipher to produce a bit pattern to XOR the
  208. * next block with.
  209. *
  210. * This is a stream cipher mode and does not require padding.
  211. */
  212. var CFB = (C_mode.CFB = function () {
  213. // Call parent constructor
  214. Mode.apply(this, arguments);
  215. });
  216. // Inherit from Mode
  217. var CFB_prototype = (CFB.prototype = new Mode());
  218. // Override padding
  219. CFB_prototype._padding = C_pad.NoPadding;
  220. // Concrete steps for Mode template
  221. CFB_prototype._doEncrypt = function (cipher, m, iv) {
  222. var blockSizeInBytes = cipher._blocksize * 4;
  223. var keystream = iv.slice(0); // Encrypt each byte
  224. for (var i = 0; i < m.length; i++) {
  225. var j = i % blockSizeInBytes;
  226. if (j == 0) {
  227. cipher._encryptblock(keystream, 0);
  228. }
  229. m[i] ^= keystream[j];
  230. keystream[j] = m[i];
  231. }
  232. };
  233. CFB_prototype._doDecrypt = function (cipher, c, iv) {
  234. var blockSizeInBytes = cipher._blocksize * 4;
  235. var keystream = iv.slice(0); // Encrypt each byte
  236. for (var i = 0; i < c.length; i++) {
  237. var j = i % blockSizeInBytes;
  238. if (j == 0) {
  239. cipher._encryptblock(keystream, 0);
  240. }
  241. var b = c[i];
  242. c[i] ^= keystream[j];
  243. keystream[j] = b;
  244. }
  245. };
  246. /**
  247. * Output feed back
  248. *
  249. * The cipher repeatedly encrypts its own output. The output is XORed with the
  250. * plain text to produce the cipher text.
  251. *
  252. * This is a stream cipher mode and does not require padding.
  253. */
  254. var OFB = (C_mode.OFB = function () {
  255. // Call parent constructor
  256. Mode.apply(this, arguments);
  257. });
  258. // Inherit from Mode
  259. var OFB_prototype = (OFB.prototype = new Mode());
  260. // Override padding
  261. OFB_prototype._padding = C_pad.NoPadding;
  262. // Concrete steps for Mode template
  263. OFB_prototype._doEncrypt = function (cipher, m, iv) {
  264. var blockSizeInBytes = cipher._blocksize * 4;
  265. var keystream = iv.slice(0); // Encrypt each byte
  266. for (var i = 0; i < m.length; i++) {
  267. // Generate keystream
  268. if (i % blockSizeInBytes == 0) {
  269. cipher._encryptblock(keystream, 0);
  270. }
  271. // Encrypt byte
  272. m[i] ^= keystream[i % blockSizeInBytes];
  273. }
  274. };
  275. OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
  276. /**
  277. * Counter
  278. * @author Gergely Risko
  279. *
  280. * After every block the last 4 bytes of the IV is increased by one
  281. * with carry and that IV is used for the next block.
  282. *
  283. * This is a stream cipher mode and does not require padding.
  284. */
  285. var CTR = (C_mode.CTR = function () {
  286. // Call parent constructor
  287. Mode.apply(this, arguments);
  288. });
  289. // Inherit from Mode
  290. var CTR_prototype = (CTR.prototype = new Mode());
  291. // Override padding
  292. CTR_prototype._padding = C_pad.NoPadding;
  293. CTR_prototype._doEncrypt = function (cipher, m, iv) {
  294. var blockSizeInBytes = cipher._blocksize * 4;
  295. var counter = iv.slice(0);
  296. for (var i = 0; i < m.length; ) {
  297. // do not lose iv
  298. var keystream = counter.slice(0);
  299. // Generate keystream for next block
  300. cipher._encryptblock(keystream, 0);
  301. // XOR keystream with block
  302. for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
  303. m[i] ^= keystream[j];
  304. }
  305. // Increase counter
  306. if (++counter[blockSizeInBytes - 1] == 256) {
  307. counter[blockSizeInBytes - 1] = 0;
  308. if (++counter[blockSizeInBytes - 2] == 256) {
  309. counter[blockSizeInBytes - 2] = 0;
  310. if (++counter[blockSizeInBytes - 3] == 256) {
  311. counter[blockSizeInBytes - 3] = 0;
  312. ++counter[blockSizeInBytes - 4];
  313. }
  314. }
  315. }
  316. }
  317. };
  318. CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
  319. })();