[6a3a178] | 1 | /**
|
---|
| 2 | * Supported cipher modes.
|
---|
| 3 | *
|
---|
| 4 | * @author Dave Longley
|
---|
| 5 | *
|
---|
| 6 | * Copyright (c) 2010-2014 Digital Bazaar, Inc.
|
---|
| 7 | */
|
---|
| 8 | var forge = require('./forge');
|
---|
| 9 | require('./util');
|
---|
| 10 |
|
---|
| 11 | forge.cipher = forge.cipher || {};
|
---|
| 12 |
|
---|
| 13 | // supported cipher modes
|
---|
| 14 | var modes = module.exports = forge.cipher.modes = forge.cipher.modes || {};
|
---|
| 15 |
|
---|
| 16 | /** Electronic codebook (ECB) (Don't use this; it's not secure) **/
|
---|
| 17 |
|
---|
| 18 | modes.ecb = function(options) {
|
---|
| 19 | options = options || {};
|
---|
| 20 | this.name = 'ECB';
|
---|
| 21 | this.cipher = options.cipher;
|
---|
| 22 | this.blockSize = options.blockSize || 16;
|
---|
| 23 | this._ints = this.blockSize / 4;
|
---|
| 24 | this._inBlock = new Array(this._ints);
|
---|
| 25 | this._outBlock = new Array(this._ints);
|
---|
| 26 | };
|
---|
| 27 |
|
---|
| 28 | modes.ecb.prototype.start = function(options) {};
|
---|
| 29 |
|
---|
| 30 | modes.ecb.prototype.encrypt = function(input, output, finish) {
|
---|
| 31 | // not enough input to encrypt
|
---|
| 32 | if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
|
---|
| 33 | return true;
|
---|
| 34 | }
|
---|
| 35 |
|
---|
| 36 | // get next block
|
---|
| 37 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 38 | this._inBlock[i] = input.getInt32();
|
---|
| 39 | }
|
---|
| 40 |
|
---|
| 41 | // encrypt block
|
---|
| 42 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 43 |
|
---|
| 44 | // write output
|
---|
| 45 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 46 | output.putInt32(this._outBlock[i]);
|
---|
| 47 | }
|
---|
| 48 | };
|
---|
| 49 |
|
---|
| 50 | modes.ecb.prototype.decrypt = function(input, output, finish) {
|
---|
| 51 | // not enough input to decrypt
|
---|
| 52 | if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
|
---|
| 53 | return true;
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | // get next block
|
---|
| 57 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 58 | this._inBlock[i] = input.getInt32();
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | // decrypt block
|
---|
| 62 | this.cipher.decrypt(this._inBlock, this._outBlock);
|
---|
| 63 |
|
---|
| 64 | // write output
|
---|
| 65 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 66 | output.putInt32(this._outBlock[i]);
|
---|
| 67 | }
|
---|
| 68 | };
|
---|
| 69 |
|
---|
| 70 | modes.ecb.prototype.pad = function(input, options) {
|
---|
| 71 | // add PKCS#7 padding to block (each pad byte is the
|
---|
| 72 | // value of the number of pad bytes)
|
---|
| 73 | var padding = (input.length() === this.blockSize ?
|
---|
| 74 | this.blockSize : (this.blockSize - input.length()));
|
---|
| 75 | input.fillWithByte(padding, padding);
|
---|
| 76 | return true;
|
---|
| 77 | };
|
---|
| 78 |
|
---|
| 79 | modes.ecb.prototype.unpad = function(output, options) {
|
---|
| 80 | // check for error: input data not a multiple of blockSize
|
---|
| 81 | if(options.overflow > 0) {
|
---|
| 82 | return false;
|
---|
| 83 | }
|
---|
| 84 |
|
---|
| 85 | // ensure padding byte count is valid
|
---|
| 86 | var len = output.length();
|
---|
| 87 | var count = output.at(len - 1);
|
---|
| 88 | if(count > (this.blockSize << 2)) {
|
---|
| 89 | return false;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | // trim off padding bytes
|
---|
| 93 | output.truncate(count);
|
---|
| 94 | return true;
|
---|
| 95 | };
|
---|
| 96 |
|
---|
| 97 | /** Cipher-block Chaining (CBC) **/
|
---|
| 98 |
|
---|
| 99 | modes.cbc = function(options) {
|
---|
| 100 | options = options || {};
|
---|
| 101 | this.name = 'CBC';
|
---|
| 102 | this.cipher = options.cipher;
|
---|
| 103 | this.blockSize = options.blockSize || 16;
|
---|
| 104 | this._ints = this.blockSize / 4;
|
---|
| 105 | this._inBlock = new Array(this._ints);
|
---|
| 106 | this._outBlock = new Array(this._ints);
|
---|
| 107 | };
|
---|
| 108 |
|
---|
| 109 | modes.cbc.prototype.start = function(options) {
|
---|
| 110 | // Note: legacy support for using IV residue (has security flaws)
|
---|
| 111 | // if IV is null, reuse block from previous processing
|
---|
| 112 | if(options.iv === null) {
|
---|
| 113 | // must have a previous block
|
---|
| 114 | if(!this._prev) {
|
---|
| 115 | throw new Error('Invalid IV parameter.');
|
---|
| 116 | }
|
---|
| 117 | this._iv = this._prev.slice(0);
|
---|
| 118 | } else if(!('iv' in options)) {
|
---|
| 119 | throw new Error('Invalid IV parameter.');
|
---|
| 120 | } else {
|
---|
| 121 | // save IV as "previous" block
|
---|
| 122 | this._iv = transformIV(options.iv, this.blockSize);
|
---|
| 123 | this._prev = this._iv.slice(0);
|
---|
| 124 | }
|
---|
| 125 | };
|
---|
| 126 |
|
---|
| 127 | modes.cbc.prototype.encrypt = function(input, output, finish) {
|
---|
| 128 | // not enough input to encrypt
|
---|
| 129 | if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
|
---|
| 130 | return true;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | // get next block
|
---|
| 134 | // CBC XOR's IV (or previous block) with plaintext
|
---|
| 135 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 136 | this._inBlock[i] = this._prev[i] ^ input.getInt32();
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | // encrypt block
|
---|
| 140 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 141 |
|
---|
| 142 | // write output, save previous block
|
---|
| 143 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 144 | output.putInt32(this._outBlock[i]);
|
---|
| 145 | }
|
---|
| 146 | this._prev = this._outBlock;
|
---|
| 147 | };
|
---|
| 148 |
|
---|
| 149 | modes.cbc.prototype.decrypt = function(input, output, finish) {
|
---|
| 150 | // not enough input to decrypt
|
---|
| 151 | if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
|
---|
| 152 | return true;
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | // get next block
|
---|
| 156 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 157 | this._inBlock[i] = input.getInt32();
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | // decrypt block
|
---|
| 161 | this.cipher.decrypt(this._inBlock, this._outBlock);
|
---|
| 162 |
|
---|
| 163 | // write output, save previous ciphered block
|
---|
| 164 | // CBC XOR's IV (or previous block) with ciphertext
|
---|
| 165 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 166 | output.putInt32(this._prev[i] ^ this._outBlock[i]);
|
---|
| 167 | }
|
---|
| 168 | this._prev = this._inBlock.slice(0);
|
---|
| 169 | };
|
---|
| 170 |
|
---|
| 171 | modes.cbc.prototype.pad = function(input, options) {
|
---|
| 172 | // add PKCS#7 padding to block (each pad byte is the
|
---|
| 173 | // value of the number of pad bytes)
|
---|
| 174 | var padding = (input.length() === this.blockSize ?
|
---|
| 175 | this.blockSize : (this.blockSize - input.length()));
|
---|
| 176 | input.fillWithByte(padding, padding);
|
---|
| 177 | return true;
|
---|
| 178 | };
|
---|
| 179 |
|
---|
| 180 | modes.cbc.prototype.unpad = function(output, options) {
|
---|
| 181 | // check for error: input data not a multiple of blockSize
|
---|
| 182 | if(options.overflow > 0) {
|
---|
| 183 | return false;
|
---|
| 184 | }
|
---|
| 185 |
|
---|
| 186 | // ensure padding byte count is valid
|
---|
| 187 | var len = output.length();
|
---|
| 188 | var count = output.at(len - 1);
|
---|
| 189 | if(count > (this.blockSize << 2)) {
|
---|
| 190 | return false;
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | // trim off padding bytes
|
---|
| 194 | output.truncate(count);
|
---|
| 195 | return true;
|
---|
| 196 | };
|
---|
| 197 |
|
---|
| 198 | /** Cipher feedback (CFB) **/
|
---|
| 199 |
|
---|
| 200 | modes.cfb = function(options) {
|
---|
| 201 | options = options || {};
|
---|
| 202 | this.name = 'CFB';
|
---|
| 203 | this.cipher = options.cipher;
|
---|
| 204 | this.blockSize = options.blockSize || 16;
|
---|
| 205 | this._ints = this.blockSize / 4;
|
---|
| 206 | this._inBlock = null;
|
---|
| 207 | this._outBlock = new Array(this._ints);
|
---|
| 208 | this._partialBlock = new Array(this._ints);
|
---|
| 209 | this._partialOutput = forge.util.createBuffer();
|
---|
| 210 | this._partialBytes = 0;
|
---|
| 211 | };
|
---|
| 212 |
|
---|
| 213 | modes.cfb.prototype.start = function(options) {
|
---|
| 214 | if(!('iv' in options)) {
|
---|
| 215 | throw new Error('Invalid IV parameter.');
|
---|
| 216 | }
|
---|
| 217 | // use IV as first input
|
---|
| 218 | this._iv = transformIV(options.iv, this.blockSize);
|
---|
| 219 | this._inBlock = this._iv.slice(0);
|
---|
| 220 | this._partialBytes = 0;
|
---|
| 221 | };
|
---|
| 222 |
|
---|
| 223 | modes.cfb.prototype.encrypt = function(input, output, finish) {
|
---|
| 224 | // not enough input to encrypt
|
---|
| 225 | var inputLength = input.length();
|
---|
| 226 | if(inputLength === 0) {
|
---|
| 227 | return true;
|
---|
| 228 | }
|
---|
| 229 |
|
---|
| 230 | // encrypt block
|
---|
| 231 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 232 |
|
---|
| 233 | // handle full block
|
---|
| 234 | if(this._partialBytes === 0 && inputLength >= this.blockSize) {
|
---|
| 235 | // XOR input with output, write input as output
|
---|
| 236 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 237 | this._inBlock[i] = input.getInt32() ^ this._outBlock[i];
|
---|
| 238 | output.putInt32(this._inBlock[i]);
|
---|
| 239 | }
|
---|
| 240 | return;
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | // handle partial block
|
---|
| 244 | var partialBytes = (this.blockSize - inputLength) % this.blockSize;
|
---|
| 245 | if(partialBytes > 0) {
|
---|
| 246 | partialBytes = this.blockSize - partialBytes;
|
---|
| 247 | }
|
---|
| 248 |
|
---|
| 249 | // XOR input with output, write input as partial output
|
---|
| 250 | this._partialOutput.clear();
|
---|
| 251 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 252 | this._partialBlock[i] = input.getInt32() ^ this._outBlock[i];
|
---|
| 253 | this._partialOutput.putInt32(this._partialBlock[i]);
|
---|
| 254 | }
|
---|
| 255 |
|
---|
| 256 | if(partialBytes > 0) {
|
---|
| 257 | // block still incomplete, restore input buffer
|
---|
| 258 | input.read -= this.blockSize;
|
---|
| 259 | } else {
|
---|
| 260 | // block complete, update input block
|
---|
| 261 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 262 | this._inBlock[i] = this._partialBlock[i];
|
---|
| 263 | }
|
---|
| 264 | }
|
---|
| 265 |
|
---|
| 266 | // skip any previous partial bytes
|
---|
| 267 | if(this._partialBytes > 0) {
|
---|
| 268 | this._partialOutput.getBytes(this._partialBytes);
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | if(partialBytes > 0 && !finish) {
|
---|
| 272 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 273 | partialBytes - this._partialBytes));
|
---|
| 274 | this._partialBytes = partialBytes;
|
---|
| 275 | return true;
|
---|
| 276 | }
|
---|
| 277 |
|
---|
| 278 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 279 | inputLength - this._partialBytes));
|
---|
| 280 | this._partialBytes = 0;
|
---|
| 281 | };
|
---|
| 282 |
|
---|
| 283 | modes.cfb.prototype.decrypt = function(input, output, finish) {
|
---|
| 284 | // not enough input to decrypt
|
---|
| 285 | var inputLength = input.length();
|
---|
| 286 | if(inputLength === 0) {
|
---|
| 287 | return true;
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | // encrypt block (CFB always uses encryption mode)
|
---|
| 291 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 292 |
|
---|
| 293 | // handle full block
|
---|
| 294 | if(this._partialBytes === 0 && inputLength >= this.blockSize) {
|
---|
| 295 | // XOR input with output, write input as output
|
---|
| 296 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 297 | this._inBlock[i] = input.getInt32();
|
---|
| 298 | output.putInt32(this._inBlock[i] ^ this._outBlock[i]);
|
---|
| 299 | }
|
---|
| 300 | return;
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | // handle partial block
|
---|
| 304 | var partialBytes = (this.blockSize - inputLength) % this.blockSize;
|
---|
| 305 | if(partialBytes > 0) {
|
---|
| 306 | partialBytes = this.blockSize - partialBytes;
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | // XOR input with output, write input as partial output
|
---|
| 310 | this._partialOutput.clear();
|
---|
| 311 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 312 | this._partialBlock[i] = input.getInt32();
|
---|
| 313 | this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]);
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | if(partialBytes > 0) {
|
---|
| 317 | // block still incomplete, restore input buffer
|
---|
| 318 | input.read -= this.blockSize;
|
---|
| 319 | } else {
|
---|
| 320 | // block complete, update input block
|
---|
| 321 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 322 | this._inBlock[i] = this._partialBlock[i];
|
---|
| 323 | }
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 | // skip any previous partial bytes
|
---|
| 327 | if(this._partialBytes > 0) {
|
---|
| 328 | this._partialOutput.getBytes(this._partialBytes);
|
---|
| 329 | }
|
---|
| 330 |
|
---|
| 331 | if(partialBytes > 0 && !finish) {
|
---|
| 332 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 333 | partialBytes - this._partialBytes));
|
---|
| 334 | this._partialBytes = partialBytes;
|
---|
| 335 | return true;
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 339 | inputLength - this._partialBytes));
|
---|
| 340 | this._partialBytes = 0;
|
---|
| 341 | };
|
---|
| 342 |
|
---|
| 343 | /** Output feedback (OFB) **/
|
---|
| 344 |
|
---|
| 345 | modes.ofb = function(options) {
|
---|
| 346 | options = options || {};
|
---|
| 347 | this.name = 'OFB';
|
---|
| 348 | this.cipher = options.cipher;
|
---|
| 349 | this.blockSize = options.blockSize || 16;
|
---|
| 350 | this._ints = this.blockSize / 4;
|
---|
| 351 | this._inBlock = null;
|
---|
| 352 | this._outBlock = new Array(this._ints);
|
---|
| 353 | this._partialOutput = forge.util.createBuffer();
|
---|
| 354 | this._partialBytes = 0;
|
---|
| 355 | };
|
---|
| 356 |
|
---|
| 357 | modes.ofb.prototype.start = function(options) {
|
---|
| 358 | if(!('iv' in options)) {
|
---|
| 359 | throw new Error('Invalid IV parameter.');
|
---|
| 360 | }
|
---|
| 361 | // use IV as first input
|
---|
| 362 | this._iv = transformIV(options.iv, this.blockSize);
|
---|
| 363 | this._inBlock = this._iv.slice(0);
|
---|
| 364 | this._partialBytes = 0;
|
---|
| 365 | };
|
---|
| 366 |
|
---|
| 367 | modes.ofb.prototype.encrypt = function(input, output, finish) {
|
---|
| 368 | // not enough input to encrypt
|
---|
| 369 | var inputLength = input.length();
|
---|
| 370 | if(input.length() === 0) {
|
---|
| 371 | return true;
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | // encrypt block (OFB always uses encryption mode)
|
---|
| 375 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 376 |
|
---|
| 377 | // handle full block
|
---|
| 378 | if(this._partialBytes === 0 && inputLength >= this.blockSize) {
|
---|
| 379 | // XOR input with output and update next input
|
---|
| 380 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 381 | output.putInt32(input.getInt32() ^ this._outBlock[i]);
|
---|
| 382 | this._inBlock[i] = this._outBlock[i];
|
---|
| 383 | }
|
---|
| 384 | return;
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | // handle partial block
|
---|
| 388 | var partialBytes = (this.blockSize - inputLength) % this.blockSize;
|
---|
| 389 | if(partialBytes > 0) {
|
---|
| 390 | partialBytes = this.blockSize - partialBytes;
|
---|
| 391 | }
|
---|
| 392 |
|
---|
| 393 | // XOR input with output
|
---|
| 394 | this._partialOutput.clear();
|
---|
| 395 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 396 | this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
|
---|
| 397 | }
|
---|
| 398 |
|
---|
| 399 | if(partialBytes > 0) {
|
---|
| 400 | // block still incomplete, restore input buffer
|
---|
| 401 | input.read -= this.blockSize;
|
---|
| 402 | } else {
|
---|
| 403 | // block complete, update input block
|
---|
| 404 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 405 | this._inBlock[i] = this._outBlock[i];
|
---|
| 406 | }
|
---|
| 407 | }
|
---|
| 408 |
|
---|
| 409 | // skip any previous partial bytes
|
---|
| 410 | if(this._partialBytes > 0) {
|
---|
| 411 | this._partialOutput.getBytes(this._partialBytes);
|
---|
| 412 | }
|
---|
| 413 |
|
---|
| 414 | if(partialBytes > 0 && !finish) {
|
---|
| 415 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 416 | partialBytes - this._partialBytes));
|
---|
| 417 | this._partialBytes = partialBytes;
|
---|
| 418 | return true;
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 422 | inputLength - this._partialBytes));
|
---|
| 423 | this._partialBytes = 0;
|
---|
| 424 | };
|
---|
| 425 |
|
---|
| 426 | modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt;
|
---|
| 427 |
|
---|
| 428 | /** Counter (CTR) **/
|
---|
| 429 |
|
---|
| 430 | modes.ctr = function(options) {
|
---|
| 431 | options = options || {};
|
---|
| 432 | this.name = 'CTR';
|
---|
| 433 | this.cipher = options.cipher;
|
---|
| 434 | this.blockSize = options.blockSize || 16;
|
---|
| 435 | this._ints = this.blockSize / 4;
|
---|
| 436 | this._inBlock = null;
|
---|
| 437 | this._outBlock = new Array(this._ints);
|
---|
| 438 | this._partialOutput = forge.util.createBuffer();
|
---|
| 439 | this._partialBytes = 0;
|
---|
| 440 | };
|
---|
| 441 |
|
---|
| 442 | modes.ctr.prototype.start = function(options) {
|
---|
| 443 | if(!('iv' in options)) {
|
---|
| 444 | throw new Error('Invalid IV parameter.');
|
---|
| 445 | }
|
---|
| 446 | // use IV as first input
|
---|
| 447 | this._iv = transformIV(options.iv, this.blockSize);
|
---|
| 448 | this._inBlock = this._iv.slice(0);
|
---|
| 449 | this._partialBytes = 0;
|
---|
| 450 | };
|
---|
| 451 |
|
---|
| 452 | modes.ctr.prototype.encrypt = function(input, output, finish) {
|
---|
| 453 | // not enough input to encrypt
|
---|
| 454 | var inputLength = input.length();
|
---|
| 455 | if(inputLength === 0) {
|
---|
| 456 | return true;
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | // encrypt block (CTR always uses encryption mode)
|
---|
| 460 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 461 |
|
---|
| 462 | // handle full block
|
---|
| 463 | if(this._partialBytes === 0 && inputLength >= this.blockSize) {
|
---|
| 464 | // XOR input with output
|
---|
| 465 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 466 | output.putInt32(input.getInt32() ^ this._outBlock[i]);
|
---|
| 467 | }
|
---|
| 468 | } else {
|
---|
| 469 | // handle partial block
|
---|
| 470 | var partialBytes = (this.blockSize - inputLength) % this.blockSize;
|
---|
| 471 | if(partialBytes > 0) {
|
---|
| 472 | partialBytes = this.blockSize - partialBytes;
|
---|
| 473 | }
|
---|
| 474 |
|
---|
| 475 | // XOR input with output
|
---|
| 476 | this._partialOutput.clear();
|
---|
| 477 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 478 | this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
|
---|
| 479 | }
|
---|
| 480 |
|
---|
| 481 | if(partialBytes > 0) {
|
---|
| 482 | // block still incomplete, restore input buffer
|
---|
| 483 | input.read -= this.blockSize;
|
---|
| 484 | }
|
---|
| 485 |
|
---|
| 486 | // skip any previous partial bytes
|
---|
| 487 | if(this._partialBytes > 0) {
|
---|
| 488 | this._partialOutput.getBytes(this._partialBytes);
|
---|
| 489 | }
|
---|
| 490 |
|
---|
| 491 | if(partialBytes > 0 && !finish) {
|
---|
| 492 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 493 | partialBytes - this._partialBytes));
|
---|
| 494 | this._partialBytes = partialBytes;
|
---|
| 495 | return true;
|
---|
| 496 | }
|
---|
| 497 |
|
---|
| 498 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 499 | inputLength - this._partialBytes));
|
---|
| 500 | this._partialBytes = 0;
|
---|
| 501 | }
|
---|
| 502 |
|
---|
| 503 | // block complete, increment counter (input block)
|
---|
| 504 | inc32(this._inBlock);
|
---|
| 505 | };
|
---|
| 506 |
|
---|
| 507 | modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt;
|
---|
| 508 |
|
---|
| 509 | /** Galois/Counter Mode (GCM) **/
|
---|
| 510 |
|
---|
| 511 | modes.gcm = function(options) {
|
---|
| 512 | options = options || {};
|
---|
| 513 | this.name = 'GCM';
|
---|
| 514 | this.cipher = options.cipher;
|
---|
| 515 | this.blockSize = options.blockSize || 16;
|
---|
| 516 | this._ints = this.blockSize / 4;
|
---|
| 517 | this._inBlock = new Array(this._ints);
|
---|
| 518 | this._outBlock = new Array(this._ints);
|
---|
| 519 | this._partialOutput = forge.util.createBuffer();
|
---|
| 520 | this._partialBytes = 0;
|
---|
| 521 |
|
---|
| 522 | // R is actually this value concatenated with 120 more zero bits, but
|
---|
| 523 | // we only XOR against R so the other zeros have no effect -- we just
|
---|
| 524 | // apply this value to the first integer in a block
|
---|
| 525 | this._R = 0xE1000000;
|
---|
| 526 | };
|
---|
| 527 |
|
---|
| 528 | modes.gcm.prototype.start = function(options) {
|
---|
| 529 | if(!('iv' in options)) {
|
---|
| 530 | throw new Error('Invalid IV parameter.');
|
---|
| 531 | }
|
---|
| 532 | // ensure IV is a byte buffer
|
---|
| 533 | var iv = forge.util.createBuffer(options.iv);
|
---|
| 534 |
|
---|
| 535 | // no ciphered data processed yet
|
---|
| 536 | this._cipherLength = 0;
|
---|
| 537 |
|
---|
| 538 | // default additional data is none
|
---|
| 539 | var additionalData;
|
---|
| 540 | if('additionalData' in options) {
|
---|
| 541 | additionalData = forge.util.createBuffer(options.additionalData);
|
---|
| 542 | } else {
|
---|
| 543 | additionalData = forge.util.createBuffer();
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 | // default tag length is 128 bits
|
---|
| 547 | if('tagLength' in options) {
|
---|
| 548 | this._tagLength = options.tagLength;
|
---|
| 549 | } else {
|
---|
| 550 | this._tagLength = 128;
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 | // if tag is given, ensure tag matches tag length
|
---|
| 554 | this._tag = null;
|
---|
| 555 | if(options.decrypt) {
|
---|
| 556 | // save tag to check later
|
---|
| 557 | this._tag = forge.util.createBuffer(options.tag).getBytes();
|
---|
| 558 | if(this._tag.length !== (this._tagLength / 8)) {
|
---|
| 559 | throw new Error('Authentication tag does not match tag length.');
|
---|
| 560 | }
|
---|
| 561 | }
|
---|
| 562 |
|
---|
| 563 | // create tmp storage for hash calculation
|
---|
| 564 | this._hashBlock = new Array(this._ints);
|
---|
| 565 |
|
---|
| 566 | // no tag generated yet
|
---|
| 567 | this.tag = null;
|
---|
| 568 |
|
---|
| 569 | // generate hash subkey
|
---|
| 570 | // (apply block cipher to "zero" block)
|
---|
| 571 | this._hashSubkey = new Array(this._ints);
|
---|
| 572 | this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey);
|
---|
| 573 |
|
---|
| 574 | // generate table M
|
---|
| 575 | // use 4-bit tables (32 component decomposition of a 16 byte value)
|
---|
| 576 | // 8-bit tables take more space and are known to have security
|
---|
| 577 | // vulnerabilities (in native implementations)
|
---|
| 578 | this.componentBits = 4;
|
---|
| 579 | this._m = this.generateHashTable(this._hashSubkey, this.componentBits);
|
---|
| 580 |
|
---|
| 581 | // Note: support IV length different from 96 bits? (only supporting
|
---|
| 582 | // 96 bits is recommended by NIST SP-800-38D)
|
---|
| 583 | // generate J_0
|
---|
| 584 | var ivLength = iv.length();
|
---|
| 585 | if(ivLength === 12) {
|
---|
| 586 | // 96-bit IV
|
---|
| 587 | this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1];
|
---|
| 588 | } else {
|
---|
| 589 | // IV is NOT 96-bits
|
---|
| 590 | this._j0 = [0, 0, 0, 0];
|
---|
| 591 | while(iv.length() > 0) {
|
---|
| 592 | this._j0 = this.ghash(
|
---|
| 593 | this._hashSubkey, this._j0,
|
---|
| 594 | [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]);
|
---|
| 595 | }
|
---|
| 596 | this._j0 = this.ghash(
|
---|
| 597 | this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8)));
|
---|
| 598 | }
|
---|
| 599 |
|
---|
| 600 | // generate ICB (initial counter block)
|
---|
| 601 | this._inBlock = this._j0.slice(0);
|
---|
| 602 | inc32(this._inBlock);
|
---|
| 603 | this._partialBytes = 0;
|
---|
| 604 |
|
---|
| 605 | // consume authentication data
|
---|
| 606 | additionalData = forge.util.createBuffer(additionalData);
|
---|
| 607 | // save additional data length as a BE 64-bit number
|
---|
| 608 | this._aDataLength = from64To32(additionalData.length() * 8);
|
---|
| 609 | // pad additional data to 128 bit (16 byte) block size
|
---|
| 610 | var overflow = additionalData.length() % this.blockSize;
|
---|
| 611 | if(overflow) {
|
---|
| 612 | additionalData.fillWithByte(0, this.blockSize - overflow);
|
---|
| 613 | }
|
---|
| 614 | this._s = [0, 0, 0, 0];
|
---|
| 615 | while(additionalData.length() > 0) {
|
---|
| 616 | this._s = this.ghash(this._hashSubkey, this._s, [
|
---|
| 617 | additionalData.getInt32(),
|
---|
| 618 | additionalData.getInt32(),
|
---|
| 619 | additionalData.getInt32(),
|
---|
| 620 | additionalData.getInt32()
|
---|
| 621 | ]);
|
---|
| 622 | }
|
---|
| 623 | };
|
---|
| 624 |
|
---|
| 625 | modes.gcm.prototype.encrypt = function(input, output, finish) {
|
---|
| 626 | // not enough input to encrypt
|
---|
| 627 | var inputLength = input.length();
|
---|
| 628 | if(inputLength === 0) {
|
---|
| 629 | return true;
|
---|
| 630 | }
|
---|
| 631 |
|
---|
| 632 | // encrypt block
|
---|
| 633 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 634 |
|
---|
| 635 | // handle full block
|
---|
| 636 | if(this._partialBytes === 0 && inputLength >= this.blockSize) {
|
---|
| 637 | // XOR input with output
|
---|
| 638 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 639 | output.putInt32(this._outBlock[i] ^= input.getInt32());
|
---|
| 640 | }
|
---|
| 641 | this._cipherLength += this.blockSize;
|
---|
| 642 | } else {
|
---|
| 643 | // handle partial block
|
---|
| 644 | var partialBytes = (this.blockSize - inputLength) % this.blockSize;
|
---|
| 645 | if(partialBytes > 0) {
|
---|
| 646 | partialBytes = this.blockSize - partialBytes;
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 | // XOR input with output
|
---|
| 650 | this._partialOutput.clear();
|
---|
| 651 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 652 | this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
|
---|
| 653 | }
|
---|
| 654 |
|
---|
| 655 | if(partialBytes <= 0 || finish) {
|
---|
| 656 | // handle overflow prior to hashing
|
---|
| 657 | if(finish) {
|
---|
| 658 | // get block overflow
|
---|
| 659 | var overflow = inputLength % this.blockSize;
|
---|
| 660 | this._cipherLength += overflow;
|
---|
| 661 | // truncate for hash function
|
---|
| 662 | this._partialOutput.truncate(this.blockSize - overflow);
|
---|
| 663 | } else {
|
---|
| 664 | this._cipherLength += this.blockSize;
|
---|
| 665 | }
|
---|
| 666 |
|
---|
| 667 | // get output block for hashing
|
---|
| 668 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 669 | this._outBlock[i] = this._partialOutput.getInt32();
|
---|
| 670 | }
|
---|
| 671 | this._partialOutput.read -= this.blockSize;
|
---|
| 672 | }
|
---|
| 673 |
|
---|
| 674 | // skip any previous partial bytes
|
---|
| 675 | if(this._partialBytes > 0) {
|
---|
| 676 | this._partialOutput.getBytes(this._partialBytes);
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 | if(partialBytes > 0 && !finish) {
|
---|
| 680 | // block still incomplete, restore input buffer, get partial output,
|
---|
| 681 | // and return early
|
---|
| 682 | input.read -= this.blockSize;
|
---|
| 683 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 684 | partialBytes - this._partialBytes));
|
---|
| 685 | this._partialBytes = partialBytes;
|
---|
| 686 | return true;
|
---|
| 687 | }
|
---|
| 688 |
|
---|
| 689 | output.putBytes(this._partialOutput.getBytes(
|
---|
| 690 | inputLength - this._partialBytes));
|
---|
| 691 | this._partialBytes = 0;
|
---|
| 692 | }
|
---|
| 693 |
|
---|
| 694 | // update hash block S
|
---|
| 695 | this._s = this.ghash(this._hashSubkey, this._s, this._outBlock);
|
---|
| 696 |
|
---|
| 697 | // increment counter (input block)
|
---|
| 698 | inc32(this._inBlock);
|
---|
| 699 | };
|
---|
| 700 |
|
---|
| 701 | modes.gcm.prototype.decrypt = function(input, output, finish) {
|
---|
| 702 | // not enough input to decrypt
|
---|
| 703 | var inputLength = input.length();
|
---|
| 704 | if(inputLength < this.blockSize && !(finish && inputLength > 0)) {
|
---|
| 705 | return true;
|
---|
| 706 | }
|
---|
| 707 |
|
---|
| 708 | // encrypt block (GCM always uses encryption mode)
|
---|
| 709 | this.cipher.encrypt(this._inBlock, this._outBlock);
|
---|
| 710 |
|
---|
| 711 | // increment counter (input block)
|
---|
| 712 | inc32(this._inBlock);
|
---|
| 713 |
|
---|
| 714 | // update hash block S
|
---|
| 715 | this._hashBlock[0] = input.getInt32();
|
---|
| 716 | this._hashBlock[1] = input.getInt32();
|
---|
| 717 | this._hashBlock[2] = input.getInt32();
|
---|
| 718 | this._hashBlock[3] = input.getInt32();
|
---|
| 719 | this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock);
|
---|
| 720 |
|
---|
| 721 | // XOR hash input with output
|
---|
| 722 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 723 | output.putInt32(this._outBlock[i] ^ this._hashBlock[i]);
|
---|
| 724 | }
|
---|
| 725 |
|
---|
| 726 | // increment cipher data length
|
---|
| 727 | if(inputLength < this.blockSize) {
|
---|
| 728 | this._cipherLength += inputLength % this.blockSize;
|
---|
| 729 | } else {
|
---|
| 730 | this._cipherLength += this.blockSize;
|
---|
| 731 | }
|
---|
| 732 | };
|
---|
| 733 |
|
---|
| 734 | modes.gcm.prototype.afterFinish = function(output, options) {
|
---|
| 735 | var rval = true;
|
---|
| 736 |
|
---|
| 737 | // handle overflow
|
---|
| 738 | if(options.decrypt && options.overflow) {
|
---|
| 739 | output.truncate(this.blockSize - options.overflow);
|
---|
| 740 | }
|
---|
| 741 |
|
---|
| 742 | // handle authentication tag
|
---|
| 743 | this.tag = forge.util.createBuffer();
|
---|
| 744 |
|
---|
| 745 | // concatenate additional data length with cipher length
|
---|
| 746 | var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8));
|
---|
| 747 |
|
---|
| 748 | // include lengths in hash
|
---|
| 749 | this._s = this.ghash(this._hashSubkey, this._s, lengths);
|
---|
| 750 |
|
---|
| 751 | // do GCTR(J_0, S)
|
---|
| 752 | var tag = [];
|
---|
| 753 | this.cipher.encrypt(this._j0, tag);
|
---|
| 754 | for(var i = 0; i < this._ints; ++i) {
|
---|
| 755 | this.tag.putInt32(this._s[i] ^ tag[i]);
|
---|
| 756 | }
|
---|
| 757 |
|
---|
| 758 | // trim tag to length
|
---|
| 759 | this.tag.truncate(this.tag.length() % (this._tagLength / 8));
|
---|
| 760 |
|
---|
| 761 | // check authentication tag
|
---|
| 762 | if(options.decrypt && this.tag.bytes() !== this._tag) {
|
---|
| 763 | rval = false;
|
---|
| 764 | }
|
---|
| 765 |
|
---|
| 766 | return rval;
|
---|
| 767 | };
|
---|
| 768 |
|
---|
| 769 | /**
|
---|
| 770 | * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois
|
---|
| 771 | * field multiplication. The field, GF(2^128), is defined by the polynomial:
|
---|
| 772 | *
|
---|
| 773 | * x^128 + x^7 + x^2 + x + 1
|
---|
| 774 | *
|
---|
| 775 | * Which is represented in little-endian binary form as: 11100001 (0xe1). When
|
---|
| 776 | * the value of a coefficient is 1, a bit is set. The value R, is the
|
---|
| 777 | * concatenation of this value and 120 zero bits, yielding a 128-bit value
|
---|
| 778 | * which matches the block size.
|
---|
| 779 | *
|
---|
| 780 | * This function will multiply two elements (vectors of bytes), X and Y, in
|
---|
| 781 | * the field GF(2^128). The result is initialized to zero. For each bit of
|
---|
| 782 | * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd)
|
---|
| 783 | * by the current value of Y. For each bit, the value of Y will be raised by
|
---|
| 784 | * a power of x (multiplied by the polynomial x). This can be achieved by
|
---|
| 785 | * shifting Y once to the right. If the current value of Y, prior to being
|
---|
| 786 | * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial.
|
---|
| 787 | * Otherwise, we must divide by R after shifting to find the remainder.
|
---|
| 788 | *
|
---|
| 789 | * @param x the first block to multiply by the second.
|
---|
| 790 | * @param y the second block to multiply by the first.
|
---|
| 791 | *
|
---|
| 792 | * @return the block result of the multiplication.
|
---|
| 793 | */
|
---|
| 794 | modes.gcm.prototype.multiply = function(x, y) {
|
---|
| 795 | var z_i = [0, 0, 0, 0];
|
---|
| 796 | var v_i = y.slice(0);
|
---|
| 797 |
|
---|
| 798 | // calculate Z_128 (block has 128 bits)
|
---|
| 799 | for(var i = 0; i < 128; ++i) {
|
---|
| 800 | // if x_i is 0, Z_{i+1} = Z_i (unchanged)
|
---|
| 801 | // else Z_{i+1} = Z_i ^ V_i
|
---|
| 802 | // get x_i by finding 32-bit int position, then left shift 1 by remainder
|
---|
| 803 | var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32));
|
---|
| 804 | if(x_i) {
|
---|
| 805 | z_i[0] ^= v_i[0];
|
---|
| 806 | z_i[1] ^= v_i[1];
|
---|
| 807 | z_i[2] ^= v_i[2];
|
---|
| 808 | z_i[3] ^= v_i[3];
|
---|
| 809 | }
|
---|
| 810 |
|
---|
| 811 | // if LSB(V_i) is 1, V_i = V_i >> 1
|
---|
| 812 | // else V_i = (V_i >> 1) ^ R
|
---|
| 813 | this.pow(v_i, v_i);
|
---|
| 814 | }
|
---|
| 815 |
|
---|
| 816 | return z_i;
|
---|
| 817 | };
|
---|
| 818 |
|
---|
| 819 | modes.gcm.prototype.pow = function(x, out) {
|
---|
| 820 | // if LSB(x) is 1, x = x >>> 1
|
---|
| 821 | // else x = (x >>> 1) ^ R
|
---|
| 822 | var lsb = x[3] & 1;
|
---|
| 823 |
|
---|
| 824 | // always do x >>> 1:
|
---|
| 825 | // starting with the rightmost integer, shift each integer to the right
|
---|
| 826 | // one bit, pulling in the bit from the integer to the left as its top
|
---|
| 827 | // most bit (do this for the last 3 integers)
|
---|
| 828 | for(var i = 3; i > 0; --i) {
|
---|
| 829 | out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31);
|
---|
| 830 | }
|
---|
| 831 | // shift the first integer normally
|
---|
| 832 | out[0] = x[0] >>> 1;
|
---|
| 833 |
|
---|
| 834 | // if lsb was not set, then polynomial had a degree of 127 and doesn't
|
---|
| 835 | // need to divided; otherwise, XOR with R to find the remainder; we only
|
---|
| 836 | // need to XOR the first integer since R technically ends w/120 zero bits
|
---|
| 837 | if(lsb) {
|
---|
| 838 | out[0] ^= this._R;
|
---|
| 839 | }
|
---|
| 840 | };
|
---|
| 841 |
|
---|
| 842 | modes.gcm.prototype.tableMultiply = function(x) {
|
---|
| 843 | // assumes 4-bit tables are used
|
---|
| 844 | var z = [0, 0, 0, 0];
|
---|
| 845 | for(var i = 0; i < 32; ++i) {
|
---|
| 846 | var idx = (i / 8) | 0;
|
---|
| 847 | var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF;
|
---|
| 848 | var ah = this._m[i][x_i];
|
---|
| 849 | z[0] ^= ah[0];
|
---|
| 850 | z[1] ^= ah[1];
|
---|
| 851 | z[2] ^= ah[2];
|
---|
| 852 | z[3] ^= ah[3];
|
---|
| 853 | }
|
---|
| 854 | return z;
|
---|
| 855 | };
|
---|
| 856 |
|
---|
| 857 | /**
|
---|
| 858 | * A continuing version of the GHASH algorithm that operates on a single
|
---|
| 859 | * block. The hash block, last hash value (Ym) and the new block to hash
|
---|
| 860 | * are given.
|
---|
| 861 | *
|
---|
| 862 | * @param h the hash block.
|
---|
| 863 | * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash.
|
---|
| 864 | * @param x the block to hash.
|
---|
| 865 | *
|
---|
| 866 | * @return the hashed value (Ym).
|
---|
| 867 | */
|
---|
| 868 | modes.gcm.prototype.ghash = function(h, y, x) {
|
---|
| 869 | y[0] ^= x[0];
|
---|
| 870 | y[1] ^= x[1];
|
---|
| 871 | y[2] ^= x[2];
|
---|
| 872 | y[3] ^= x[3];
|
---|
| 873 | return this.tableMultiply(y);
|
---|
| 874 | //return this.multiply(y, h);
|
---|
| 875 | };
|
---|
| 876 |
|
---|
| 877 | /**
|
---|
| 878 | * Precomputes a table for multiplying against the hash subkey. This
|
---|
| 879 | * mechanism provides a substantial speed increase over multiplication
|
---|
| 880 | * performed without a table. The table-based multiplication this table is
|
---|
| 881 | * for solves X * H by multiplying each component of X by H and then
|
---|
| 882 | * composing the results together using XOR.
|
---|
| 883 | *
|
---|
| 884 | * This function can be used to generate tables with different bit sizes
|
---|
| 885 | * for the components, however, this implementation assumes there are
|
---|
| 886 | * 32 components of X (which is a 16 byte vector), therefore each component
|
---|
| 887 | * takes 4-bits (so the table is constructed with bits=4).
|
---|
| 888 | *
|
---|
| 889 | * @param h the hash subkey.
|
---|
| 890 | * @param bits the bit size for a component.
|
---|
| 891 | */
|
---|
| 892 | modes.gcm.prototype.generateHashTable = function(h, bits) {
|
---|
| 893 | // TODO: There are further optimizations that would use only the
|
---|
| 894 | // first table M_0 (or some variant) along with a remainder table;
|
---|
| 895 | // this can be explored in the future
|
---|
| 896 | var multiplier = 8 / bits;
|
---|
| 897 | var perInt = 4 * multiplier;
|
---|
| 898 | var size = 16 * multiplier;
|
---|
| 899 | var m = new Array(size);
|
---|
| 900 | for(var i = 0; i < size; ++i) {
|
---|
| 901 | var tmp = [0, 0, 0, 0];
|
---|
| 902 | var idx = (i / perInt) | 0;
|
---|
| 903 | var shft = ((perInt - 1 - (i % perInt)) * bits);
|
---|
| 904 | tmp[idx] = (1 << (bits - 1)) << shft;
|
---|
| 905 | m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits);
|
---|
| 906 | }
|
---|
| 907 | return m;
|
---|
| 908 | };
|
---|
| 909 |
|
---|
| 910 | /**
|
---|
| 911 | * Generates a table for multiplying against the hash subkey for one
|
---|
| 912 | * particular component (out of all possible component values).
|
---|
| 913 | *
|
---|
| 914 | * @param mid the pre-multiplied value for the middle key of the table.
|
---|
| 915 | * @param bits the bit size for a component.
|
---|
| 916 | */
|
---|
| 917 | modes.gcm.prototype.generateSubHashTable = function(mid, bits) {
|
---|
| 918 | // compute the table quickly by minimizing the number of
|
---|
| 919 | // POW operations -- they only need to be performed for powers of 2,
|
---|
| 920 | // all other entries can be composed from those powers using XOR
|
---|
| 921 | var size = 1 << bits;
|
---|
| 922 | var half = size >>> 1;
|
---|
| 923 | var m = new Array(size);
|
---|
| 924 | m[half] = mid.slice(0);
|
---|
| 925 | var i = half >>> 1;
|
---|
| 926 | while(i > 0) {
|
---|
| 927 | // raise m0[2 * i] and store in m0[i]
|
---|
| 928 | this.pow(m[2 * i], m[i] = []);
|
---|
| 929 | i >>= 1;
|
---|
| 930 | }
|
---|
| 931 | i = 2;
|
---|
| 932 | while(i < half) {
|
---|
| 933 | for(var j = 1; j < i; ++j) {
|
---|
| 934 | var m_i = m[i];
|
---|
| 935 | var m_j = m[j];
|
---|
| 936 | m[i + j] = [
|
---|
| 937 | m_i[0] ^ m_j[0],
|
---|
| 938 | m_i[1] ^ m_j[1],
|
---|
| 939 | m_i[2] ^ m_j[2],
|
---|
| 940 | m_i[3] ^ m_j[3]
|
---|
| 941 | ];
|
---|
| 942 | }
|
---|
| 943 | i *= 2;
|
---|
| 944 | }
|
---|
| 945 | m[0] = [0, 0, 0, 0];
|
---|
| 946 | /* Note: We could avoid storing these by doing composition during multiply
|
---|
| 947 | calculate top half using composition by speed is preferred. */
|
---|
| 948 | for(i = half + 1; i < size; ++i) {
|
---|
| 949 | var c = m[i ^ half];
|
---|
| 950 | m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]];
|
---|
| 951 | }
|
---|
| 952 | return m;
|
---|
| 953 | };
|
---|
| 954 |
|
---|
| 955 | /** Utility functions */
|
---|
| 956 |
|
---|
| 957 | function transformIV(iv, blockSize) {
|
---|
| 958 | if(typeof iv === 'string') {
|
---|
| 959 | // convert iv string into byte buffer
|
---|
| 960 | iv = forge.util.createBuffer(iv);
|
---|
| 961 | }
|
---|
| 962 |
|
---|
| 963 | if(forge.util.isArray(iv) && iv.length > 4) {
|
---|
| 964 | // convert iv byte array into byte buffer
|
---|
| 965 | var tmp = iv;
|
---|
| 966 | iv = forge.util.createBuffer();
|
---|
| 967 | for(var i = 0; i < tmp.length; ++i) {
|
---|
| 968 | iv.putByte(tmp[i]);
|
---|
| 969 | }
|
---|
| 970 | }
|
---|
| 971 |
|
---|
| 972 | if(iv.length() < blockSize) {
|
---|
| 973 | throw new Error(
|
---|
| 974 | 'Invalid IV length; got ' + iv.length() +
|
---|
| 975 | ' bytes and expected ' + blockSize + ' bytes.');
|
---|
| 976 | }
|
---|
| 977 |
|
---|
| 978 | if(!forge.util.isArray(iv)) {
|
---|
| 979 | // convert iv byte buffer into 32-bit integer array
|
---|
| 980 | var ints = [];
|
---|
| 981 | var blocks = blockSize / 4;
|
---|
| 982 | for(var i = 0; i < blocks; ++i) {
|
---|
| 983 | ints.push(iv.getInt32());
|
---|
| 984 | }
|
---|
| 985 | iv = ints;
|
---|
| 986 | }
|
---|
| 987 |
|
---|
| 988 | return iv;
|
---|
| 989 | }
|
---|
| 990 |
|
---|
| 991 | function inc32(block) {
|
---|
| 992 | // increment last 32 bits of block only
|
---|
| 993 | block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF;
|
---|
| 994 | }
|
---|
| 995 |
|
---|
| 996 | function from64To32(num) {
|
---|
| 997 | // convert 64-bit number to two BE Int32s
|
---|
| 998 | return [(num / 0x100000000) | 0, num & 0xFFFFFFFF];
|
---|
| 999 | }
|
---|