BlockModes.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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(0x00);
  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(0x80);
  50. for (; reqd > 1; reqd--) {
  51. message.push(0x00);
  52. }
  53. },
  54. unpad : function (message) {
  55. while (message.pop() != 0x80) {}
  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(0x00);
  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. } else {
  176. // XOR this block using previous crypted block
  177. for (var i = 0; i < blockSizeInBytes; i++)
  178. m[offset + i] ^= m[offset + i - blockSizeInBytes];
  179. }
  180. // Encrypt block
  181. cipher._encryptblock(m, offset);
  182. }
  183. };
  184. CBC_prototype._doDecrypt = function (cipher, c, iv) {
  185. var blockSizeInBytes = cipher._blocksize * 4;
  186. // At the start, the previously crypted block is the IV
  187. var prevCryptedBlock = iv;
  188. // Decrypt each block
  189. for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
  190. // Save this crypted block
  191. var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
  192. // Decrypt block
  193. cipher._decryptblock(c, offset);
  194. // XOR decrypted block using previous crypted block
  195. for (var i = 0; i < blockSizeInBytes; i++) {
  196. c[offset + i] ^= prevCryptedBlock[i];
  197. }
  198. prevCryptedBlock = thisCryptedBlock;
  199. }
  200. };
  201. /**
  202. * Cipher feed back
  203. *
  204. * The cipher output is XORed with the plain text to produce the cipher output,
  205. * which is then fed back into the cipher to produce a bit pattern to XOR the
  206. * next block with.
  207. *
  208. * This is a stream cipher mode and does not require padding.
  209. */
  210. var CFB = C_mode.CFB = function () {
  211. // Call parent constructor
  212. Mode.apply(this, arguments);
  213. };
  214. // Inherit from Mode
  215. var CFB_prototype = CFB.prototype = new Mode;
  216. // Override padding
  217. CFB_prototype._padding = C_pad.NoPadding;
  218. // Concrete steps for Mode template
  219. CFB_prototype._doEncrypt = function (cipher, m, iv) {
  220. var blockSizeInBytes = cipher._blocksize * 4,
  221. keystream = iv.slice(0);
  222. // Encrypt each byte
  223. for (var i = 0; i < m.length; i++) {
  224. var j = i % blockSizeInBytes;
  225. if (j == 0) cipher._encryptblock(keystream, 0);
  226. m[i] ^= keystream[j];
  227. keystream[j] = m[i];
  228. }
  229. };
  230. CFB_prototype._doDecrypt = function (cipher, c, iv) {
  231. var blockSizeInBytes = cipher._blocksize * 4,
  232. keystream = iv.slice(0);
  233. // Encrypt each byte
  234. for (var i = 0; i < c.length; i++) {
  235. var j = i % blockSizeInBytes;
  236. if (j == 0) cipher._encryptblock(keystream, 0);
  237. var b = c[i];
  238. c[i] ^= keystream[j];
  239. keystream[j] = b;
  240. }
  241. };
  242. /**
  243. * Output feed back
  244. *
  245. * The cipher repeatedly encrypts its own output. The output is XORed with the
  246. * plain text to produce the cipher text.
  247. *
  248. * This is a stream cipher mode and does not require padding.
  249. */
  250. var OFB = C_mode.OFB = function () {
  251. // Call parent constructor
  252. Mode.apply(this, arguments);
  253. };
  254. // Inherit from Mode
  255. var OFB_prototype = OFB.prototype = new Mode;
  256. // Override padding
  257. OFB_prototype._padding = C_pad.NoPadding;
  258. // Concrete steps for Mode template
  259. OFB_prototype._doEncrypt = function (cipher, m, iv) {
  260. var blockSizeInBytes = cipher._blocksize * 4,
  261. keystream = iv.slice(0);
  262. // Encrypt each byte
  263. for (var i = 0; i < m.length; i++) {
  264. // Generate keystream
  265. if (i % blockSizeInBytes == 0)
  266. cipher._encryptblock(keystream, 0);
  267. // Encrypt byte
  268. m[i] ^= keystream[i % blockSizeInBytes];
  269. }
  270. };
  271. OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
  272. /**
  273. * Counter
  274. * @author Gergely Risko
  275. *
  276. * After every block the last 4 bytes of the IV is increased by one
  277. * with carry and that IV is used for the next block.
  278. *
  279. * This is a stream cipher mode and does not require padding.
  280. */
  281. var CTR = C_mode.CTR = function () {
  282. // Call parent constructor
  283. Mode.apply(this, arguments);
  284. };
  285. // Inherit from Mode
  286. var CTR_prototype = CTR.prototype = new Mode;
  287. // Override padding
  288. CTR_prototype._padding = C_pad.NoPadding;
  289. CTR_prototype._doEncrypt = function (cipher, m, iv) {
  290. var blockSizeInBytes = cipher._blocksize * 4;
  291. var counter = iv.slice(0);
  292. for (var i = 0; i < m.length;) {
  293. // do not lose iv
  294. var keystream = counter.slice(0);
  295. // Generate keystream for next block
  296. cipher._encryptblock(keystream, 0);
  297. // XOR keystream with block
  298. for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
  299. m[i] ^= keystream[j];
  300. }
  301. // Increase counter
  302. if(++(counter[blockSizeInBytes-1]) == 256) {
  303. counter[blockSizeInBytes-1] = 0;
  304. if(++(counter[blockSizeInBytes-2]) == 256) {
  305. counter[blockSizeInBytes-2] = 0;
  306. if(++(counter[blockSizeInBytes-3]) == 256) {
  307. counter[blockSizeInBytes-3] = 0;
  308. ++(counter[blockSizeInBytes-4]);
  309. }
  310. }
  311. }
  312. }
  313. };
  314. CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
  315. })();