Source: cbc.js

  1. /** @fileOverview CBC mode implementation
  2. *
  3. * @author Emily Stark
  4. * @author Mike Hamburg
  5. * @author Dan Boneh
  6. */
  7. if (sjcl.beware === undefined) {
  8. sjcl.beware = {};
  9. }
  10. sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."
  11. ] = function() {
  12. /**
  13. * Dangerous: CBC mode with PKCS#5 padding.
  14. * @namespace
  15. * @author Emily Stark
  16. * @author Mike Hamburg
  17. * @author Dan Boneh
  18. */
  19. sjcl.mode.cbc = {
  20. /** The name of the mode.
  21. * @constant
  22. */
  23. name: "cbc",
  24. /** Encrypt in CBC mode with PKCS#5 padding.
  25. * @param {Object} prp The block cipher. It must have a block size of 16 bytes.
  26. * @param {bitArray} plaintext The plaintext data.
  27. * @param {bitArray} iv The initialization value.
  28. * @param {bitArray} [adata=[]] The authenticated data. Must be empty.
  29. * @return The encrypted data, an array of bytes.
  30. * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
  31. */
  32. encrypt: function(prp, plaintext, iv, adata) {
  33. if (adata && adata.length) {
  34. throw new sjcl.exception.invalid("cbc can't authenticate data");
  35. }
  36. if (sjcl.bitArray.bitLength(iv) !== 128) {
  37. throw new sjcl.exception.invalid("cbc iv must be 128 bits");
  38. }
  39. var i,
  40. w = sjcl.bitArray,
  41. xor = w._xor4,
  42. bl = w.bitLength(plaintext),
  43. bp = 0,
  44. output = [];
  45. if (bl&7) {
  46. throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte");
  47. }
  48. for (i=0; bp+128 <= bl; i+=4, bp+=128) {
  49. /* Encrypt a non-final block */
  50. iv = prp.encrypt(xor(iv, plaintext.slice(i,i+4)));
  51. output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
  52. }
  53. /* Construct the pad. */
  54. bl = (16 - ((bl >> 3) & 15)) * 0x1010101;
  55. /* Pad and encrypt. */
  56. iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4)));
  57. output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
  58. return output;
  59. },
  60. /** Decrypt in CBC mode.
  61. * @param {Object} prp The block cipher. It must have a block size of 16 bytes.
  62. * @param {bitArray} ciphertext The ciphertext data.
  63. * @param {bitArray} iv The initialization value.
  64. * @param {bitArray} [adata=[]] The authenticated data. It must be empty.
  65. * @return The decrypted data, an array of bytes.
  66. * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
  67. * @throws {sjcl.exception.corrupt} if if the message is corrupt.
  68. */
  69. decrypt: function(prp, ciphertext, iv, adata) {
  70. if (adata && adata.length) {
  71. throw new sjcl.exception.invalid("cbc can't authenticate data");
  72. }
  73. if (sjcl.bitArray.bitLength(iv) !== 128) {
  74. throw new sjcl.exception.invalid("cbc iv must be 128 bits");
  75. }
  76. if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
  77. throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
  78. }
  79. var i,
  80. w = sjcl.bitArray,
  81. xor = w._xor4,
  82. bi, bo,
  83. output = [];
  84. adata = adata || [];
  85. for (i=0; i<ciphertext.length; i+=4) {
  86. bi = ciphertext.slice(i,i+4);
  87. bo = xor(iv,prp.decrypt(bi));
  88. output.splice(i,0,bo[0],bo[1],bo[2],bo[3]);
  89. iv = bi;
  90. }
  91. /* check and remove the pad */
  92. bi = output[i-1] & 255;
  93. if (bi === 0 || bi > 16) {
  94. throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
  95. }
  96. bo = bi * 0x1010101;
  97. if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8),
  98. w.bitSlice(output, output.length*32 - bi*8, output.length*32))) {
  99. throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
  100. }
  101. return w.bitSlice(output, 0, output.length*32 - bi*8);
  102. }
  103. };
  104. };