[Pkg-javascript-commits] [pdf.js] 83/207: Added support for decrypting PDF 1.7/2.0 Algorithm 5 revision 5 and 6. *Added AES128 Encryption *Added AES258 Encryption/Decryption *Added SHA256 *Added SHA512 *Added class to handle 8 byte integers and associated bit operations *Added SHA384 *Added routines to handle new algorithm and perform PDF2.0 hashing.
David Prévot
taffit at moszumanska.debian.org
Mon Jul 28 15:36:33 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository pdf.js.
commit 1fce2856c6c81163b9fbd701b7bb047b6df40573
Author: Daniel West <daniel.j.west at gmail.com>
Date: Sat Apr 19 02:21:32 2014 -0400
Added support for decrypting PDF 1.7/2.0 Algorithm 5 revision 5 and 6.
*Added AES128 Encryption
*Added AES258 Encryption/Decryption
*Added SHA256
*Added SHA512
*Added class to handle 8 byte integers and associated bit operations
*Added SHA384
*Added routines to handle new algorithm and perform PDF2.0 hashing.
---
src/core/crypto.js | 1386 +++++++++++++++++++++++++++++++++++++++++++---
test/unit/crypto_spec.js | 431 +++++++++++++-
2 files changed, 1745 insertions(+), 72 deletions(-)
diff --git a/src/core/crypto.js b/src/core/crypto.js
index eb5d534..150a22d 100644
--- a/src/core/crypto.js
+++ b/src/core/crypto.js
@@ -103,13 +103,11 @@ var calculateMD5 = (function calculateMD5Closure() {
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
- // chunking
- // TODO ArrayBuffer ?
var w = new Int32Array(16);
for (i = 0; i < paddedLength;) {
for (j = 0; j < 16; ++j, i += 4) {
w[j] = (padded[i] | (padded[i + 1] << 8) |
- (padded[i + 2] << 16) | (padded[i + 3] << 24));
+ (padded[i + 2] << 16) | (padded[i + 3] << 24));
}
var a = h0, b = h1, c = h2, d = h3, f, g;
for (j = 0; j < 64; ++j) {
@@ -144,22 +142,839 @@ var calculateMD5 = (function calculateMD5Closure() {
h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
]);
}
+
return hash;
})();
+var Word64 = (function Word64Closure() {
+ function Word64(highInteger, lowInteger) {
+ this.low = lowInteger >>> 0;
+ this.high = highInteger >>> 0;
+ }
+ Word64.prototype = {
+ and: function Word64_and(word) {
+ return new Word64(this.high & word.high,
+ this.low & word.low);
+ },
+ xor: function Word64_xor(word) {
+ return new Word64(this.high ^ word.high,
+ this.low ^ word.low);
+ },
+
+ or: function Word64_or(word) {
+ return new Word64(this.high | word.high,
+ this.low | word.low);
+ },
+
+ shiftRight: function Word64_shiftRight(places) {
+ if (places >= 32) {
+ return new Word64(0x00000000, this.high >>> (places - 32));
+ }
+ return new Word64(this.high >>> places,
+ (this.low >>> places) | (this.high << 32 - places));
+ },
+
+ shiftLeft: function Word64_shiftLeft(places) {
+ if (places >= 32) {
+ return new Word64(this.low << (places - 32), 0x00000000);
+ }
+ return new Word64((this.high << places) |
+ (this.low >>> 32 - places),
+ (this.low << places));
+ },
+ not: function Word64_not() {
+ return new Word64(~this.high, ~this.low);
+ },
+ plus: function Word64_plus(word) {
+ var lowAdd = this.low + word.low;
+ var highAdd = this.high + word.high;
+ if (lowAdd > 0xFFFFFFFF) {
+ highAdd += 1;
+ }
+ return new Word64((highAdd | 0) >>> 0,
+ (lowAdd | 0) >>> 0);
+ },
+ copyTo: function Word64_copyTo(bytes, offset) {
+ if (offset + bytes >= bytes.length) {
+ error('insufficient byte array length');
+ }
+ bytes[offset] = (this.high >>> 24) & 0xFF;
+ bytes[offset + 1] = (this.high >>> 16) & 0xFF;
+ bytes[offset + 2] = (this.high >>> 8) & 0xFF;
+ bytes[offset + 3] = (this.high) & 0xFF;
+ bytes[offset + 4] = (this.low >>> 24) & 0xFF;
+ bytes[offset + 5] = (this.low >>> 16) & 0xFF;
+ bytes[offset + 6] = (this.low >>> 8) & 0xFF;
+ bytes[offset + 7] = (this.low) & 0xFF;
+ }
+ };
+ return Word64;
+})();
+
+var calculateSHA256 = (function calculateSHA256Closure() {
+ function rotr(x, n) {
+ return (x >>> n) | (x << 32 - n);
+ }
+
+ function ch(x, y, z) {
+ return (x & y) ^ (~x & z);
+ }
+
+ function maj(x, y, z) {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ function sigma(x) {
+ return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
+ }
+
+ function sigmaPrime(x) {
+ return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
+ }
+
+ function littleSigma(x) {
+ return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
+ }
+
+ function littleSigmaPrime(x) {
+ return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
+ }
+
+ var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
+
+ function hash(data, offset, length) {
+ // initial hash values
+ var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372,
+ h3 = 0xa54ff53a, h4 = 0x510e527f, h5 = 0x9b05688c,
+ h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
+ // pre-processing
+ var paddedLength = Math.ceil((length + 9) / 64) * 64;
+ var padded = new Uint8Array(paddedLength);
+ var i, j, n;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ n = paddedLength - 8;
+ while (i < n) {
+ padded[i++] = 0;
+ }
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = (length >>> 29) & 0xFF;
+ padded[i++] = (length >> 21) & 0xFF;
+ padded[i++] = (length >> 13) & 0xFF;
+ padded[i++] = (length >> 5) & 0xFF;
+ padded[i++] = (length << 3) & 0xFF;
+ var w = new Uint32Array(64);
+ //for each 512 bit block
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 64; ++j) {
+ if (j < 16) {
+ w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |
+ (padded[i + 2] << 8) | (padded[i + 3]));
+ i += 4;
+ } else {
+ w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +
+ littleSigma(w[j - 15]) + w[j - 16] | 0;
+ }
+ }
+ var a = h0, b = h1, c = h2, d = h3, e = h4,
+ f = h5, g = h6, h = h7, t1, t2;
+ for (j = 0; j < 64; ++j) {
+ t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
+ t2 = sigma(a) + maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = (d + t1) | 0;
+ d = c;
+ c = b;
+ b = a;
+ a = (t1 + t2) | 0;
+ }
+ h0 = (h0 + a) | 0;
+ h1 = (h1 + b) | 0;
+ h2 = (h2 + c) | 0;
+ h3 = (h3 + d) | 0;
+ h4 = (h4 + e) | 0;
+ h5 = (h5 + f) | 0;
+ h6 = (h6 + g) | 0;
+ h7 = (h7 + h) | 0;
+ }
+ return new Uint8Array([
+ (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,
+ (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,
+ (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,
+ (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,
+ (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,
+ (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,
+ (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,
+ (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF
+ ]);
+ }
+
+ return hash;
+})();
+
+var calculateSHA512 = (function calculateSHA512Closure() {
+ function rotr(x, n) {
+ return (x.shiftRight(n)).or(x.shiftLeft(64 - n));
+ }
+
+ function ch(x, y, z) {
+ return (x.and(y)).xor(x.not().and(z));
+ }
+
+ function maj(x, y, z) {
+ return (x.and(y)).xor(x.and(z)).xor(y.and(z));
+ }
+
+ function sigma(x) {
+ return rotr(x, 28).xor(rotr(x, 34)).xor(rotr(x, 39));
+ }
+
+ function sigmaPrime(x) {
+ return rotr(x, 14).xor(rotr(x, 18)).xor(rotr(x, 41));
+ }
+
+ function littleSigma(x) {
+ return rotr(x, 1).xor(rotr(x, 8)).xor(x.shiftRight(7));
+ }
+
+ function littleSigmaPrime(x) {
+ return rotr(x, 19).xor(rotr(x, 61)).xor(x.shiftRight(6));
+ }
+
+ var k = [
+ new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),
+ new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),
+ new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),
+ new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118),
+ new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe),
+ new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2),
+ new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1),
+ new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694),
+ new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3),
+ new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65),
+ new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483),
+ new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5),
+ new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210),
+ new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4),
+ new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725),
+ new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70),
+ new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926),
+ new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df),
+ new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8),
+ new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b),
+ new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001),
+ new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30),
+ new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910),
+ new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8),
+ new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53),
+ new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8),
+ new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb),
+ new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3),
+ new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60),
+ new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec),
+ new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9),
+ new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b),
+ new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207),
+ new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178),
+ new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6),
+ new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b),
+ new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493),
+ new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c),
+ new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a),
+ new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];
+
+ function hash(data, offset, length, mode384) {
+ mode384 = !!mode384;
+ // initial hash values
+ var h0, h1, h2, h3, h4, h5, h6, h7;
+ if (!mode384) {
+ h0 = new Word64(0x6a09e667, 0xf3bcc908);
+ h1 = new Word64(0xbb67ae85, 0x84caa73b);
+ h2 = new Word64(0x3c6ef372, 0xfe94f82b);
+ h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
+ h4 = new Word64(0x510e527f, 0xade682d1);
+ h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
+ h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
+ h7 = new Word64(0x5be0cd19, 0x137e2179);
+ }
+ else {
+ //SHA384 is exactly the same
+ //except with different starting values and a trimmed result
+ h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
+ h1 = new Word64(0x629a292a, 0x367cd507);
+ h2 = new Word64(0x9159015a, 0x3070dd17);
+ h3 = new Word64(0x152fecd8, 0xf70e5939);
+ h4 = new Word64(0x67332667, 0xffc00b31);
+ h5 = new Word64(0x8eb44a87, 0x68581511);
+ h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
+ h7 = new Word64(0x47b5481d, 0xbefa4fa4);
+ }
+
+ // pre-processing
+ var paddedLength = Math.ceil((length + 17) / 128) * 128;
+ var padded = new Uint8Array(paddedLength);
+ var i, j, n;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ n = paddedLength - 16;
+ while (i < n) {
+ padded[i++] = 0;
+ }
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = (length >>> 29) & 0xFF;
+ padded[i++] = (length >> 21) & 0xFF;
+ padded[i++] = (length >> 13) & 0xFF;
+ padded[i++] = (length >> 5) & 0xFF;
+ padded[i++] = (length << 3) & 0xFF;
+
+ var w = new Array(128);
+ //for each 1024 bit block
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 80; ++j) {
+ if (j < 16) {
+ var value = new Word64(padded[i] << 24 |(padded[i + 1] << 16) |
+ (padded[i + 2] << 8) | (padded[i + 3]),
+ (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |
+ (padded[i + 6]) << 8 | (padded[i + 7]));
+ w[j] = value;
+ i += 8;
+ } else {
+ w[j] = littleSigmaPrime(w[j - 2])
+ .plus(w[j - 7])
+ .plus(littleSigma(w[j - 15]))
+ .plus(w[j - 16]);
+ }
+
+ }
+ var a = h0, b = h1, c = h2, d = h3,
+ e = h4, f = h5, g = h6, h = h7,
+ t1, t2;
+ for (j = 0; j < 80; ++j) {
+ t1 = h.plus(sigmaPrime(e))
+ .plus(ch(e, f, g))
+ .plus(k[j])
+ .plus(w[j]);
+ t2 = sigma(a).plus(maj(a, b, c));
+ h = g;
+ g = f;
+ f = e;
+ e = (d.plus(t1));
+ d = c;
+ c = b;
+ b = a;
+ a = (t1.plus(t2));
+ }
+ h0 = (h0.plus(a));
+ h1 = (h1.plus(b));
+ h2 = (h2.plus(c));
+ h3 = (h3.plus(d));
+ h4 = (h4.plus(e));
+ h5 = (h5.plus(f));
+ h6 = (h6.plus(g));
+ h7 = (h7.plus(h));
+ }
+
+ var result;
+ if (!mode384) {
+ result = new Uint8Array(64);
+ h0.copyTo(result,0);
+ h1.copyTo(result,8);
+ h2.copyTo(result,16);
+ h3.copyTo(result,24);
+ h4.copyTo(result,32);
+ h5.copyTo(result,40);
+ h6.copyTo(result,48);
+ h7.copyTo(result,56);
+ }
+ else {
+ result = new Uint8Array(48);
+ h0.copyTo(result,0);
+ h1.copyTo(result,8);
+ h2.copyTo(result,16);
+ h3.copyTo(result,24);
+ h4.copyTo(result,32);
+ h5.copyTo(result,40);
+ }
+ return result;
+ }
+
+ return hash;
+})();
+var calculateSHA384 = (function calculateSHA384Closure() {
+ function hash(data, offset, length) {
+ return calculateSHA512(data, offset, length, true);
+ }
+
+ return hash;
+})();
+var NullCipher = (function NullCipherClosure() {
+ function NullCipher() {
+ }
+
+ NullCipher.prototype = {
+ decryptBlock: function NullCipher_decryptBlock(data) {
+ return data;
+ }
+ };
+
+ return NullCipher;
+})();
+
+var AES128Cipher = (function AES128CipherClosure() {
+ var rcon = new Uint8Array([
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
+ 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
+ 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
+ 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
+ 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
+ 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
+ 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
+ 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d]);
+
+ var s = new Uint8Array([
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+ 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+ 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+ 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+ 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+ 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+ 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+ 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+ 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+ 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+ 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+ 0xb0, 0x54, 0xbb, 0x16]);
+
+ var inv_s = new Uint8Array([
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
+ 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
+ 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
+ 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
+ 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
+ 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
+ 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
+ 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
+ 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
+ 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0c, 0x7d]);
+ var mixCol = new Uint8Array(256);
+ for (var i = 0; i < 256; i++) {
+ if (i < 128) {
+ mixCol[i] = i << 1;
+ } else {
+ mixCol[i] = (i << 1) ^ 0x1b;
+ }
+ }
+ var mix = new Uint32Array([
+ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
+ 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
+ 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
+ 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
+ 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
+ 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
+ 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
+ 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
+ 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
+ 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
+ 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
+ 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
+ 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
+ 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
+ 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
+ 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
+ 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
+ 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
+ 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
+ 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
+ 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
+ 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
+ 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
+ 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
+ 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
+ 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
+ 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
+ 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
+ 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
+ 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
+ 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
+ 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
+ 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
+ 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
+ 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
+ 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
+ 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
+ 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
+ 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
+ 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
+ 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
+ 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
+ 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
+
+ function expandKey128(cipherKey) {
+ var b = 176, result = new Uint8Array(b);
+ result.set(cipherKey);
+ for (var j = 16, i = 1; j < b; ++i) {
+ // RotWord
+ var t1 = result[j - 3], t2 = result[j - 2],
+ t3 = result[j - 1], t4 = result[j - 4];
+ // SubWord
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ // Rcon
+ t1 = t1 ^ rcon[i];
+ for (var n = 0; n < 4; ++n) {
+ result[j] = (t1 ^= result[j - 16]);
+ j++;
+ result[j] = (t2 ^= result[j - 16]);
+ j++;
+ result[j] = (t3 ^= result[j - 16]);
+ j++;
+ result[j] = (t4 ^= result[j - 16]);
+ j++;
+ }
+ }
+ return result;
+ }
+
+ function decrypt128(input, key) {
+ var state = new Uint8Array(16);
+ state.set(input);
+ var i, j, k;
+ var t, u, v;
+ // AddRoundKey
+ for (j = 0, k = 160; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ for (i = 9; i >= 1; --i) {
+ // InvShiftRows
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ // InvSubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = inv_s[state[j]];
+ }
+ // AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ // InvMixColumns
+ for (j = 0; j < 16; j += 4) {
+ var s0 = mix[state[j]], s1 = mix[state[j + 1]],
+ s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
+ t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
+ (s3 >>> 24) ^ (s3 << 8));
+ state[j] = (t >>> 24) & 0xFF;
+ state[j + 1] = (t >> 16) & 0xFF;
+ state[j + 2] = (t >> 8) & 0xFF;
+ state[j + 3] = t & 0xFF;
+ }
+ }
+ // InvShiftRows
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ for (j = 0; j < 16; ++j) {
+ // InvSubBytes
+ state[j] = inv_s[state[j]];
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
+ return state;
+ }
-var NullCipher = (function NullCipherClosure() {
- function NullCipher() {}
+ function encrypt128(input, key) {
+ var t, u, v, k;
+ var state = new Uint8Array(16);
+ state.set(input);
+ for (j = 0; j < 16; ++j) {
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
- NullCipher.prototype = {
- decryptBlock: function NullCipher_decryptBlock(data) {
- return data;
+ for (i = 1; i < 10; i++) {
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //MixColumns
+ for (var j = 0; j < 16; j += 4) {
+ var s0 = state[j + 0], s1 = state[j + 1];
+ var s2 = state[j + 2], s3 = state[j + 3];
+ t = s0 ^ s1 ^ s2 ^ s3;
+ state[j + 0] ^= t ^ mixCol[s0 ^ s1];
+ state[j + 1] ^= t ^ mixCol[s1 ^ s2];
+ state[j + 2] ^= t ^ mixCol[s2 ^ s3];
+ state[j + 3] ^= t ^ mixCol[s3 ^ s0];
+ }
+ //AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ }
+
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //AddRoundKey
+ for (j = 0, k = 160; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ return state;
+ }
+
+ function AES128Cipher(key) {
+ this.key = expandKey128(key);
+ this.buffer = new Uint8Array(16);
+ this.bufferPosition = 0;
+ }
+
+ function decryptBlock2(data, finalize) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [], iv = this.iv;
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ // buffer is full, decrypting
+ var plain = decrypt128(buffer, this.key);
+ // xor-ing the IV vector to get plain text
+ for (j = 0; j < 16; ++j) {
+ plain[j] ^= iv[j];
+ }
+ iv = buffer;
+ result.push(plain);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ if (finalize) {
+ // undo a padding that is described in RFC 2898
+ var lastBlock = result[result.length - 1];
+ outputLength -= lastBlock[15];
+ result[result.length - 1] = lastBlock.subarray(0, 16 - lastBlock[15]);
+ }
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
+ }
+
+ AES128Cipher.prototype = {
+ decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {
+ var i, sourceLength = data.length;
+ var buffer = this.buffer, bufferLength = this.bufferPosition;
+ // waiting for IV values -- they are at the start of the stream
+ for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
+ buffer[bufferLength] = data[i];
+ }
+ if (bufferLength < 16) {
+ // need more data
+ this.bufferLength = bufferLength;
+ return new Uint8Array([]);
+ }
+ this.iv = buffer;
+ this.buffer = new Uint8Array(16);
+ this.bufferLength = 0;
+ // starting decryption
+ this.decryptBlock = decryptBlock2;
+ return this.decryptBlock(data.subarray(16), finalize);
+ },
+ encrypt: function AES128Cipher_encrypt(data, iv) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [];
+ if (!iv) {
+ iv = new Uint8Array(16);
+ }
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ for (j = 0; j < 16; ++j) {
+ buffer[j] ^= iv[j];
+ }
+
+ // buffer is full, encrypting
+ var cipher = encrypt128(buffer, this.key);
+ iv = cipher;
+ result.push(cipher);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
}
};
- return NullCipher;
+ return AES128Cipher;
})();
-var AES128Cipher = (function AES128CipherClosure() {
+var AES256Cipher = (function AES256CipherClosure() {
var rcon = new Uint8Array([
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
@@ -232,6 +1047,14 @@ var AES128Cipher = (function AES128CipherClosure() {
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d]);
+ var mixCol = new Uint8Array(256);
+ for (var i = 0; i < 256; i++) {
+ if (i < 128) {
+ mixCol[i] = i << 1;
+ } else {
+ mixCol[i] = (i << 1) ^ 0x1b;
+ }
+ }
var mix = new Uint32Array([
0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
@@ -277,44 +1100,76 @@ var AES128Cipher = (function AES128CipherClosure() {
0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
- function expandKey128(cipherKey) {
- var b = 176, result = new Uint8Array(b);
+ function expandKey256(cipherKey) {
+ var b = 240, result = new Uint8Array(b);
+ var r = 1;
+
result.set(cipherKey);
- for (var j = 16, i = 1; j < b; ++i) {
- // RotWord
- var t1 = result[j - 3], t2 = result[j - 2],
+ for (var j = 32, i = 1; j < b; ++i) {
+ if (j % 32 === 16) {
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ } else if (j % 32 === 0) {
+ // RotWord
+ var t1 = result[j - 3], t2 = result[j - 2],
t3 = result[j - 1], t4 = result[j - 4];
- // SubWord
- t1 = s[t1]; t2 = s[t2]; t3 = s[t3]; t4 = s[t4];
- // Rcon
- t1 = t1 ^ rcon[i];
+ // SubWord
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ // Rcon
+ t1 = t1 ^ r;
+ if ((r <<= 1) >= 256) {
+ r = (r ^ 0x1b) & 0xFF;
+ }
+ }
+
for (var n = 0; n < 4; ++n) {
- result[j] = (t1 ^= result[j - 16]); j++;
- result[j] = (t2 ^= result[j - 16]); j++;
- result[j] = (t3 ^= result[j - 16]); j++;
- result[j] = (t4 ^= result[j - 16]); j++;
+ result[j] = (t1 ^= result[j - 32]);
+ j++;
+ result[j] = (t2 ^= result[j - 32]);
+ j++;
+ result[j] = (t3 ^= result[j - 32]);
+ j++;
+ result[j] = (t4 ^= result[j - 32]);
+ j++;
}
}
return result;
}
- function decrypt128(input, key) {
+ function decrypt256(input, key) {
var state = new Uint8Array(16);
state.set(input);
var i, j, k;
var t, u, v;
// AddRoundKey
- for (j = 0, k = 160; j < 16; ++j, ++k) {
+ for (j = 0, k = 224; j < 16; ++j, ++k) {
state[j] ^= key[k];
}
- for (i = 9; i >= 1; --i) {
+ for (i = 13; i >= 1; --i) {
// InvShiftRows
- t = state[13]; state[13] = state[9]; state[9] = state[5];
- state[5] = state[1]; state[1] = t;
- t = state[14]; u = state[10]; state[14] = state[6];
- state[10] = state[2]; state[6] = t; state[2] = u;
- t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
- state[11] = t; state[7] = u; state[3] = v;
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
// InvSubBytes
for (j = 0; j < 16; ++j) {
state[j] = inv_s[state[j]];
@@ -336,12 +1191,24 @@ var AES128Cipher = (function AES128CipherClosure() {
}
}
// InvShiftRows
- t = state[13]; state[13] = state[9]; state[9] = state[5];
- state[5] = state[1]; state[1] = t;
- t = state[14]; u = state[10]; state[14] = state[6];
- state[10] = state[2]; state[6] = t; state[2] = u;
- t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
- state[11] = t; state[7] = u; state[3] = v;
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
for (j = 0; j < 16; ++j) {
// InvSubBytes
state[j] = inv_s[state[j]];
@@ -351,8 +1218,89 @@ var AES128Cipher = (function AES128CipherClosure() {
return state;
}
- function AES128Cipher(key) {
- this.key = expandKey128(key);
+ function encrypt256(input, key) {
+ var t, u, v, k;
+ var state = new Uint8Array(16);
+ state.set(input);
+ for (j = 0; j < 16; ++j) {
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
+
+ for (i = 1; i < 14; i++) {
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //MixColumns
+ for (var j = 0; j < 16; j += 4) {
+ var s0 = state[j + 0], s1 = state[j + 1];
+ var s2 = state[j + 2], s3 = state[j + 3];
+ t = s0 ^ s1 ^ s2 ^ s3;
+ state[j + 0] ^= t ^ mixCol[s0 ^ s1];
+ state[j + 1] ^= t ^ mixCol[s1 ^ s2];
+ state[j + 2] ^= t ^ mixCol[s2 ^ s3];
+ state[j + 3] ^= t ^ mixCol[s3 ^ s0];
+ }
+ //AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ }
+
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //AddRoundKey
+ for (j = 0, k = 224; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+
+ return state;
+
+ }
+
+ function AES256Cipher(key) {
+ this.key = expandKey256(key);
this.buffer = new Uint8Array(16);
this.bufferPosition = 0;
}
@@ -361,14 +1309,15 @@ var AES128Cipher = (function AES128CipherClosure() {
var i, j, ii, sourceLength = data.length,
buffer = this.buffer, bufferLength = this.bufferPosition,
result = [], iv = this.iv;
+
for (i = 0; i < sourceLength; ++i) {
buffer[bufferLength] = data[i];
++bufferLength;
if (bufferLength < 16) {
continue;
}
- // buffer is full, decrypting
- var plain = decrypt128(buffer, this.key);
+ // buffer is full, encrypting
+ var plain = decrypt256(buffer, this.key);
// xor-ing the IV vector to get plain text
for (j = 0; j < 16; ++j) {
plain[j] ^= iv[j];
@@ -398,31 +1347,267 @@ var AES128Cipher = (function AES128CipherClosure() {
output.set(result[i], j);
}
return output;
+
}
- AES128Cipher.prototype = {
- decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {
+ AES256Cipher.prototype = {
+ decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) {
var i, sourceLength = data.length;
var buffer = this.buffer, bufferLength = this.bufferPosition;
- // waiting for IV values -- they are at the start of the stream
- for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
- buffer[bufferLength] = data[i];
- }
- if (bufferLength < 16) {
- // need more data
- this.bufferLength = bufferLength;
- return new Uint8Array([]);
+ // if not supplied an IV wait for IV values
+ // they are at the start of the stream
+ if (iv) {
+ this.iv = iv;
+ } else {
+ for (i = 0; bufferLength < 16 &&
+ i < sourceLength; ++i, ++bufferLength) {
+ buffer[bufferLength] = data[i];
+ }
+ if (bufferLength < 16) {
+ //need more data
+ this.bufferLength = bufferLength;
+ return new Uint8Array([]);
+ }
+ this.iv = buffer;
+ data = data.subarray(16);
}
- this.iv = buffer;
this.buffer = new Uint8Array(16);
this.bufferLength = 0;
// starting decryption
this.decryptBlock = decryptBlock2;
- return this.decryptBlock(data.subarray(16), finalize);
+ return this.decryptBlock(data, finalize);
+ },
+ encrypt: function AES256Cipher_encrypt(data, iv) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [];
+ if (!iv) {
+ iv = new Uint8Array(16);
+ }
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ for (j = 0; j < 16; ++j) {
+ buffer[j] ^= iv[j];
+ }
+
+ // buffer is full, encrypting
+ var cipher = encrypt256(buffer, this.key);
+ this.iv = cipher;
+ result.push(cipher);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
}
};
- return AES128Cipher;
+ return AES256Cipher;
+})();
+
+var PDF17= (function PDF17Closure() {
+
+ function compareByteArrays(array1, array2) {
+ if (array1.length !== array2.length) {
+ return false;
+ }
+ for (var i = 0; i < array1.length; i++) {
+ if (array1[i] !== array2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function PDF17() {
+ }
+
+ PDF17.prototype = {
+ checkOwnerPassword: function PDF17_checkOwnerPassword(password,
+ ownerValidationSalt,
+ userBytes,
+ ownerPassword) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerValidationSalt, password.length);
+ hashData.set(userBytes, password.length + ownerValidationSalt.length);
+ var result = calculateSHA256(hashData, 0, hashData.length);
+ return compareByteArrays(result, ownerPassword);
+ },
+ checkUserPassword: function PDF17_checkUserPassword(password,
+ userValidationSalt,
+ userPassword) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userValidationSalt, password.length);
+ var result = calculateSHA256(hashData, 0, hashData.length);
+ return compareByteArrays(result, userPassword);
+ },
+ getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes,
+ ownerEncryption) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerKeySalt, password.length);
+ hashData.set(userBytes, password.length + ownerKeySalt.length);
+ var key = calculateSHA256(hashData, 0, hashData.length);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(ownerEncryption,
+ false,
+ new Uint8Array(16));
+
+ },
+ getUserKey: function PDF17_getUserKey(password, userKeySalt,
+ userEncryption) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userKeySalt, password.length);
+ //key is the decryption key for the UE string
+ var key = calculateSHA256(hashData, 0, hashData.length);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(userEncryption,
+ false,
+ new Uint8Array(16));
+ }
+ };
+ return PDF17;
+})();
+
+var PDF20 = (function PDF20Closure() {
+
+ function concatArrays(array1, array2) {
+ var t = new Uint8Array(array1.length + array2.length);
+ t.set(array1, 0);
+ t.set(array2, array1.length);
+ return t;
+ }
+
+ function calculatePDF20Hash(password, input, userBytes) {
+ //This refers to Algorithm 2.B as defined in ISO 32000-2
+ var k = calculateSHA256(input, 0, input.length).subarray(0, 32);
+ var e = [0];
+ var i = 0;
+ while (i < 64 || e[e.length - 1] > i - 32) {
+ var arrayLength = password.length + k.length + userBytes.length;
+
+ var k1 = new Uint8Array(arrayLength * 64);
+ var array = concatArrays(password, k);
+ array = concatArrays(array, userBytes);
+ for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) {
+ k1.set(array, pos);
+ }
+ //AES128 CBC NO PADDING with
+ //first 16 bytes of k as the key and the second 16 as the iv.
+ var cipher = new AES128Cipher(k.subarray(0, 16));
+ e = cipher.encrypt(k1, k.subarray(16, 32));
+ //Now we have to take the first 16 bytes of an unsigned
+ //big endian integer... and compute the remainder
+ //modulo 3.... That is a fairly large number and
+ //JavaScript isn't going to handle that well...
+ //So we're using a trick that allows us to perform
+ //modulo math byte by byte
+ var remainder = 0;
+ for (var z = 0; z < 16; z++) {
+ remainder *= (256 % 3);
+ remainder %= 3;
+ remainder += ((e[z] >>> 0) % 3);
+ remainder %= 3;
+ }
+ if (remainder === 0) {
+ k = calculateSHA256(e, 0, e.length);
+ }
+ else if (remainder === 1) {
+ k = calculateSHA384(e, 0, e.length);
+ }
+ else if (remainder === 2) {
+ k = calculateSHA512(e, 0, e.length);
+ }
+ i++;
+ }
+ return k.subarray(0, 32);
+ }
+
+ function PDF20() {
+ }
+
+ function compareByteArrays(array1, array2) {
+ if (array1.length !== array2.length) {
+ return false;
+ }
+ for (var i = 0; i < array1.length; i++) {
+ if (array1[i] !== array2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ PDF20.prototype = {
+ hash: function PDF20_hash(password, concatBytes, userBytes) {
+ return calculatePDF20Hash(password, concatBytes, userBytes);
+ },
+ checkOwnerPassword: function PDF20_checkOwnerPassword(password,
+ ownerValidationSalt,
+ userBytes,
+ ownerPassword) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerValidationSalt, password.length);
+ hashData.set(userBytes, password.length + ownerValidationSalt.length);
+ var result = calculatePDF20Hash(password, hashData, userBytes);
+ return compareByteArrays(result, ownerPassword);
+ },
+ checkUserPassword: function PDF20_checkUserPassword(password,
+ userValidationSalt,
+ userPassword) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userValidationSalt, password.length);
+ var result = calculatePDF20Hash(password, hashData, []);
+ return compareByteArrays(result, userPassword);
+ },
+ getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes,
+ ownerEncryption) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerKeySalt, password.length);
+ hashData.set(userBytes, password.length + ownerKeySalt.length);
+ var key = calculatePDF20Hash(password, hashData, userBytes);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(ownerEncryption,
+ false,
+ new Uint8Array(16));
+
+ },
+ getUserKey: function PDF20_getUserKey(password, userKeySalt,
+ userEncryption) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userKeySalt, password.length);
+ //key is the decryption key for the UE string
+ var key = calculatePDF20Hash(password, hashData, []);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(userEncryption,
+ false,
+ new Uint8Array(16));
+ }
+ };
+ return PDF20;
})();
var CipherTransform = (function CipherTransformClosure() {
@@ -430,6 +1615,7 @@ var CipherTransform = (function CipherTransformClosure() {
this.stringCipherConstructor = stringCipherConstructor;
this.streamCipherConstructor = streamCipherConstructor;
}
+
CipherTransform.prototype = {
createStream: function CipherTransform_createStream(stream, length) {
var cipher = new this.streamCipherConstructor();
@@ -456,6 +1642,38 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
+ function createEncryptionKey20(revision, password, ownerPassword,
+ ownerValidationSalt, ownerKeySalt, uBytes,
+ userPassword, userValidationSalt, userKeySalt,
+ ownerEncryption, userEncryption, perms) {
+ if (password) {
+ var passwordLength = Math.min(127, password.length);
+ password = password.subarray(0, passwordLength);
+ } else {
+ password = [];
+ }
+ var pdfAlgorithm;
+ if (revision === 6) {
+ pdfAlgorithm = new PDF20();
+ } else {
+ pdfAlgorithm = new PDF17();
+ }
+
+ if (pdfAlgorithm) {
+ if (pdfAlgorithm.checkUserPassword(password, userValidationSalt,
+ userPassword)) {
+ return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
+ } else if (pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt,
+ uBytes,
+ ownerPassword)) {
+ return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes,
+ ownerEncryption);
+ }
+ }
+
+ return null;
+ }
+
function prepareKeyData(fileId, password, ownerPassword, userPassword,
flags, revision, keyLength, encryptMetadata) {
var hashDataSize = 40 + ownerPassword.length + fileId.length;
@@ -516,7 +1734,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
checkData = cipher.encryptBlock(checkData);
}
for (j = 0, n = checkData.length; j < n; ++j) {
- if (userPassword[j] != checkData[j]) {
+ if (userPassword[j] !== checkData[j]) {
return null;
}
}
@@ -524,7 +1742,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
cipher = new ARCFourCipher(encryptionKey);
checkData = cipher.encryptBlock(defaultPasswordBytes);
for (j = 0, n = checkData.length; j < n; ++j) {
- if (userPassword[j] != checkData[j]) {
+ if (userPassword[j] !== checkData[j]) {
return null;
}
}
@@ -572,13 +1790,14 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
function CipherTransformFactory(dict, fileId, password) {
var filter = dict.get('Filter');
- if (!isName(filter) || filter.name != 'Standard') {
+ if (!isName(filter) || filter.name !== 'Standard') {
error('unknown encryption method');
}
this.dict = dict;
var algorithm = dict.get('V');
if (!isInt(algorithm) ||
- (algorithm != 1 && algorithm != 2 && algorithm != 4)) {
+ (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&
+ algorithm !== 5)) {
error('unsupported encryption algorithm');
}
this.algorithm = algorithm;
@@ -593,8 +1812,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);
var flags = dict.get('P');
var revision = dict.get('R');
- var encryptMetadata = (algorithm == 4 && // meaningful when V is 4
- dict.get('EncryptMetadata') !== false); // makes true as default value
+ // meaningful when V is 4 or 5
+ var encryptMetadata = ((algorithm === 4 || algorithm === 5) &&
+ dict.get('EncryptMetadata') !== false);
this.encryptMetadata = encryptMetadata;
var fileIdBytes = stringToBytes(fileId);
@@ -603,9 +1823,29 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
passwordBytes = stringToBytes(password);
}
- var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
- ownerPassword, userPassword, flags,
- revision, keyLength, encryptMetadata);
+ var encryptionKey;
+ if (algorithm !== 5) {
+ encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
+ ownerPassword, userPassword, flags,
+ revision, keyLength, encryptMetadata);
+ }
+ else {
+ var ownerValidationSalt = stringToBytes(dict.get('O')).subarray(32, 40);
+ var ownerKeySalt = stringToBytes(dict.get('O')).subarray(40, 48);
+ var uBytes = stringToBytes(dict.get('U')).subarray(0, 48);
+ var userValidationSalt = stringToBytes(dict.get('U')).subarray(32, 40);
+ var userKeySalt = stringToBytes(dict.get('U')).subarray(40, 48);
+ var ownerEncryption = stringToBytes(dict.get('OE'));
+ var userEncryption = stringToBytes(dict.get('UE'));
+ var perms = stringToBytes(dict.get('Perms'));
+ encryptionKey =
+ createEncryptionKey20(revision, passwordBytes,
+ ownerPassword, ownerValidationSalt,
+ ownerKeySalt, uBytes,
+ userPassword, userValidationSalt,
+ userKeySalt, ownerEncryption,
+ userEncryption, perms);
+ }
if (!encryptionKey && !password) {
throw new PasswordException('No password given',
PasswordResponses.NEED_PASSWORD);
@@ -625,7 +1865,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
this.encryptionKey = encryptionKey;
- if (algorithm == 4) {
+ if (algorithm >= 4) {
this.cf = dict.get('CF');
this.stmf = dict.get('StmF') || identityName;
this.strf = dict.get('StrF') || identityName;
@@ -659,28 +1899,33 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
if (cryptFilter !== null && cryptFilter !== undefined) {
cfm = cryptFilter.get('CFM');
}
- if (!cfm || cfm.name == 'None') {
+ if (!cfm || cfm.name === 'None') {
return function cipherTransformFactoryBuildCipherConstructorNone() {
return new NullCipher();
};
}
- if ('V2' == cfm.name) {
+ if ('V2' === cfm.name) {
return function cipherTransformFactoryBuildCipherConstructorV2() {
return new ARCFourCipher(buildObjectKey(num, gen, key, false));
};
}
- if ('AESV2' == cfm.name) {
+ if ('AESV2' === cfm.name) {
return function cipherTransformFactoryBuildCipherConstructorAESV2() {
return new AES128Cipher(buildObjectKey(num, gen, key, true));
};
}
+ if ('AESV3' === cfm.name) {
+ return function cipherTransformFactoryBuildCipherConstructorAESV3() {
+ return new AES256Cipher(key);
+ };
+ }
error('Unknown crypto method');
}
CipherTransformFactory.prototype = {
createCipherTransform:
function CipherTransformFactory_createCipherTransform(num, gen) {
- if (this.algorithm == 4) {
+ if (this.algorithm === 4 || this.algorithm === 5) {
return new CipherTransform(
buildCipherConstructor(this.cf, this.stmf,
num, gen, this.encryptionKey),
@@ -697,5 +1942,4 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
};
return CipherTransformFactory;
-})();
-
+})();
\ No newline at end of file
diff --git a/test/unit/crypto_spec.js b/test/unit/crypto_spec.js
index e17f2b1..d59d321 100644
--- a/test/unit/crypto_spec.js
+++ b/test/unit/crypto_spec.js
@@ -1,7 +1,8 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* globals expect, it, describe, calculateMD5, ARCFourCipher, Name,
- CipherTransformFactory */
+ CipherTransformFactory, calculateSHA256, calculateSHA384,
+ calculateSHA512, AES128Cipher, AES256Cipher, PDF17, PDF20*/
'use strict';
@@ -186,8 +187,309 @@ describe('crypto', function() {
expect(result).toEqual(expected);
});
});
+
+ describe('calculateSHA256', function() {
+ it('should properly hash abc', function() {
+ var input, result, expected;
+ input = string2binary('abc');
+ result = calculateSHA256(input, 0, input.length);
+ expected = hex2binary('BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9C' +
+ 'B410FF61F20015AD');
+ expect(result).toEqual(expected);
+ });
+ it('should properly hash a multiblock input', function() {
+ var input, result, expected;
+ input = string2binary('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmno' +
+ 'mnopnopq');
+ result = calculateSHA256(input, 0, input.length);
+ expected = hex2binary('248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167' +
+ 'F6ECEDD419DB06C1');
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('calculateSHA384', function() {
+ it('should properly hash abc', function() {
+ var input, result, expected;
+ input = string2binary('abc');
+ result = calculateSHA384(input, 0, input.length);
+ expected = hex2binary('CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED163' +
+ '1A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7');
+ expect(result).toEqual(expected);
+ });
+ it('should properly hash a multiblock input', function() {
+ var input, result, expected;
+ input = string2binary('abcdefghbcdefghicdefghijdefghijkefghijklfghijklm' +
+ 'ghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrs' +
+ 'mnopqrstnopqrstu');
+ result = calculateSHA384(input, 0, input.length);
+ expected = hex2binary('09330C33F71147E83D192FC782CD1B4753111B173B3B05D2' +
+ '2FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039');
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('calculateSHA512', function() {
+ it('should properly hash abc', function() {
+ var input, result, expected;
+ input = string2binary('abc');
+ result = calculateSHA512(input, 0, input.length);
+ expected = hex2binary('DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2' +
+ '0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD' +
+ '454D4423643CE80E2A9AC94FA54CA49F');
+ expect(result).toEqual(expected);
+ });
+ it('should properly hash a multiblock input', function() {
+ var input, result, expected;
+ input = string2binary('abcdefghbcdefghicdefghijdefghijkefghijklfghijklm' +
+ 'ghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrs' +
+ 'mnopqrstnopqrstu');
+ result = calculateSHA512(input, 0, input.length);
+ expected = hex2binary('8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1' +
+ '7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A' +
+ 'C7D329EEB6DD26545E96E55B874BE909');
+ expect(result).toEqual(expected);
+ });
+ });
+
+
+
+ describe('AES128', function() {
+ describe('Encryption', function() {
+ it('should be able to encrypt a block', function() {
+ var input, key, result, expected, iv, cipher;
+ input = hex2binary('00112233445566778899aabbccddeeff');
+ key = hex2binary('000102030405060708090a0b0c0d0e0f');
+ iv = hex2binary('00000000000000000000000000000000');
+ cipher = new AES128Cipher(key);
+ result = cipher.encrypt(input,iv);
+ expected = hex2binary('69c4e0d86a7b0430d8cdb78070b4c55a');
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('Decryption', function() {
+ it('should be able to decrypt a block with IV in stream', function() {
+ var input, key, result, expected, cipher;
+ input = hex2binary('0000000000000000000000000000000069c4e0d86a7b0430d' +
+ '8cdb78070b4c55a');
+ key = hex2binary('000102030405060708090a0b0c0d0e0f');
+ cipher = new AES128Cipher(key);
+ result = cipher.decryptBlock(input);
+ expected = hex2binary('00112233445566778899aabbccddeeff');
+ expect(result).toEqual(expected);
+ });
+ });
+ });
+
+ describe('AES256', function() {
+ describe('Encryption', function() {
+ it('should be able to encrypt a block', function() {
+ var input, key, result, expected, iv, cipher;
+ input = hex2binary('00112233445566778899aabbccddeeff');
+ key = hex2binary('000102030405060708090a0b0c0d0e0f101112131415161718' +
+ '191a1b1c1d1e1f');
+ iv = hex2binary('00000000000000000000000000000000');
+ cipher = new AES256Cipher(key);
+ result = cipher.encrypt(input,iv);
+ expected = hex2binary('8ea2b7ca516745bfeafc49904b496089');
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('Decryption', function() {
+ it('should be able to decrypt a block with specified iv', function() {
+ var input, key, result, expected, cipher, iv;
+ input = hex2binary('8ea2b7ca516745bfeafc49904b496089');
+ key = hex2binary('000102030405060708090a0b0c0d0e0f101112131415161718' +
+ '191a1b1c1d1e1f');
+ iv = hex2binary('00000000000000000000000000000000');
+ cipher = new AES256Cipher(key);
+ result = cipher.decryptBlock(input,false,iv);
+ expected = hex2binary('00112233445566778899aabbccddeeff');
+ expect(result).toEqual(expected);
+ });
+ it('should be able to decrypt a block with IV in stream', function() {
+ var input, key, result, expected, cipher;
+ input = hex2binary('000000000000000000000000000000008ea2b7ca516745bf' +
+ 'eafc49904b496089');
+ key = hex2binary('000102030405060708090a0b0c0d0e0f101112131415161718' +
+ '191a1b1c1d1e1f');
+ cipher = new AES256Cipher(key);
+ result = cipher.decryptBlock(input,false);
+ expected = hex2binary('00112233445566778899aabbccddeeff');
+ expect(result).toEqual(expected);
+ });
+ });
+ });
+
+ describe('PDF17Algorithm', function() {
+ it('should correctly check a user key', function() {
+ var password, userValidation, userPassword, alg, result;
+ alg = new PDF17();
+ password = new Uint8Array([117, 115, 101, 114]);
+ userValidation = new Uint8Array([117, 169, 4, 32, 159, 101, 22, 220]);
+ userPassword = new Uint8Array([
+ 131, 242, 143, 160, 87, 2, 138, 134, 79,
+ 253, 189, 173, 224, 73, 144, 241, 190, 81,
+ 197, 15, 249, 105, 145, 151, 15, 194, 65,
+ 3, 1, 126, 187, 221]);
+ result = alg.checkUserPassword(password, userValidation, userPassword);
+ expect(result).toEqual(true);
+ });
+
+ it('should correctly check an owner key', function () {
+ var password, ownerValidation, ownerPassword, alg, result, uBytes;
+ alg = new PDF17();
+ password = new Uint8Array([111, 119, 110, 101, 114]);
+ ownerValidation = new Uint8Array([243, 118, 71, 153, 128, 17, 101, 62]);
+ ownerPassword = new Uint8Array([
+ 60, 98, 137, 35, 51, 101, 200, 152, 210,
+ 178, 226, 228, 134, 205, 163, 24, 204,
+ 126, 177, 36, 106, 50, 36, 125, 210, 172,
+ 171, 120, 222, 108, 139, 115]);
+ uBytes = new Uint8Array([
+ 131, 242, 143, 160, 87, 2, 138, 134, 79, 253,
+ 189, 173, 224, 73, 144, 241, 190, 81, 197, 15,
+ 249, 105, 145, 151, 15, 194, 65, 3, 1, 126, 187,
+ 221, 117, 169, 4, 32, 159, 101, 22, 220, 168,
+ 94, 215, 192, 100, 38, 188, 40]);
+ result = alg.checkOwnerPassword(password, ownerValidation, uBytes,
+ ownerPassword);
+ expect(result).toEqual(true);
+ });
+
+ it('should generate a file encryption key from the user key', function () {
+ var password, userKeySalt, expected, alg, result, userEncryption;
+ alg = new PDF17();
+ password = new Uint8Array([117, 115, 101, 114]);
+ userKeySalt = new Uint8Array([168, 94, 215, 192, 100, 38, 188, 40]);
+ userEncryption = new Uint8Array([
+ 35, 150, 195, 169, 245, 51, 51, 255,
+ 158, 158, 33, 242, 231, 75, 125, 190,
+ 25, 126, 172, 114, 195, 244, 137, 245,
+ 234, 165, 42, 74, 60, 38, 17, 17]);
+ result = alg.getUserKey(password, userKeySalt, userEncryption);
+ expected = new Uint8Array([
+ 63, 114, 136, 209, 87, 61, 12, 30, 249, 1,
+ 186, 144, 254, 248, 163, 153, 151, 51, 133,
+ 10, 80, 152, 206, 15, 72, 187, 231, 33, 224,
+ 239, 13, 213]);
+ expect(result).toEqual(expected);
+ });
+
+ it('should generate a file encryption key from the owner key', function () {
+ var password, ownerKeySalt, expected, alg, result, ownerEncryption;
+ var uBytes;
+ alg = new PDF17();
+ password = new Uint8Array([111, 119, 110, 101, 114]);
+ ownerKeySalt = new Uint8Array([200, 245, 242, 12, 218, 123, 24, 120]);
+ ownerEncryption = new Uint8Array([
+ 213, 202, 14, 189, 110, 76, 70, 191, 6,
+ 195, 10, 190, 157, 100, 144, 85, 8, 62,
+ 123, 178, 156, 229, 50, 40, 229, 216,
+ 54, 222, 34, 38, 106, 223]);
+ uBytes = new Uint8Array([
+ 131, 242, 143, 160, 87, 2, 138, 134, 79, 253,
+ 189, 173, 224, 73, 144, 241, 190, 81, 197, 15,
+ 249, 105, 145, 151, 15, 194, 65, 3, 1, 126, 187,
+ 221, 117, 169, 4, 32, 159, 101, 22, 220, 168,
+ 94, 215, 192, 100, 38, 188, 40]);
+ result = alg.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption);
+ expected = new Uint8Array([
+ 63, 114, 136, 209, 87, 61, 12, 30, 249, 1,
+ 186, 144, 254, 248, 163, 153, 151, 51, 133,
+ 10, 80, 152, 206, 15, 72, 187, 231, 33, 224,
+ 239, 13, 213]);
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('PDF20Algorithm', function() {
+ it('should correctly check a user key', function () {
+ var password, userValidation, userPassword, alg, result;
+ alg = new PDF20();
+ password = new Uint8Array([117, 115, 101, 114]);
+ userValidation = new Uint8Array([83, 245, 146, 101, 198, 247, 34, 198]);
+ userPassword = new Uint8Array([
+ 94, 230, 205, 75, 166, 99, 250, 76, 219,
+ 128, 17, 85, 57, 17, 33, 164, 150, 46,
+ 103, 176, 160, 156, 187, 233, 166, 223,
+ 163, 253, 147, 235, 95, 184]);
+ result = alg.checkUserPassword(password, userValidation, userPassword);
+ expect(result).toEqual(true);
+ });
+
+ it('should correctly check an owner key', function () {
+ var password, ownerValidation, ownerPassword, alg, result, uBytes;
+ alg = new PDF20();
+ password = new Uint8Array([111, 119, 110, 101, 114]);
+ ownerValidation = new Uint8Array([142, 232, 169, 208, 202, 214, 5, 185]);
+ ownerPassword = new Uint8Array([
+ 88, 232, 62, 54, 245, 26, 245, 209, 137,
+ 123, 221, 72, 199, 49, 37, 217, 31, 74,
+ 115, 167, 127, 158, 176, 77, 45, 163, 87,
+ 47, 39, 90, 217, 141]);
+ uBytes = new Uint8Array([
+ 94, 230, 205, 75, 166, 99, 250, 76, 219, 128,
+ 17, 85, 57, 17, 33, 164, 150, 46, 103, 176, 160,
+ 156, 187, 233, 166, 223, 163, 253, 147, 235, 95,
+ 184, 83, 245, 146, 101, 198, 247, 34, 198, 191,
+ 11, 16, 94, 237, 216, 20, 175]);
+ result = alg.checkOwnerPassword(password, ownerValidation, uBytes,
+ ownerPassword);
+ expect(result).toEqual(true);
+ });
+
+ it('should generate a file encryption key from the user key', function () {
+ var password, userKeySalt, expected, alg, result, userEncryption;
+ alg = new PDF20();
+ password = new Uint8Array([117, 115, 101, 114]);
+ userKeySalt = new Uint8Array([191, 11, 16, 94, 237, 216, 20, 175]);
+ userEncryption = new Uint8Array([
+ 121, 208, 2, 181, 230, 89, 156, 60, 253,
+ 143, 212, 28, 84, 180, 196, 177, 173,
+ 128, 221, 107, 46, 20, 94, 186, 135, 51,
+ 95, 24, 20, 223, 254, 36]);
+ result = alg.getUserKey(password, userKeySalt, userEncryption);
+ expected = new Uint8Array([
+ 42, 218, 213, 39, 73, 91, 72, 79, 67, 38, 248,
+ 133, 18, 189, 61, 34, 107, 79, 29, 56, 59,
+ 181, 213, 118, 113, 34, 65, 210, 87, 174, 22,
+ 239]);
+ expect(result).toEqual(expected);
+ });
+
+ it('should generate a file encryption key from the owner key', function () {
+ var password, ownerKeySalt, expected, alg, result, ownerEncryption;
+ var uBytes;
+ alg = new PDF20();
+ password = new Uint8Array([111, 119, 110, 101, 114]);
+ ownerKeySalt = new Uint8Array([29, 208, 185, 46, 11, 76, 135, 149]);
+ ownerEncryption = new Uint8Array([
+ 209, 73, 224, 77, 103, 155, 201, 181,
+ 190, 68, 223, 20, 62, 90, 56, 210, 5,
+ 240, 178, 128, 238, 124, 68, 254, 253,
+ 244, 62, 108, 208, 135, 10, 251]);
+ uBytes = new Uint8Array([
+ 94, 230, 205, 75, 166, 99, 250, 76, 219, 128,
+ 17, 85, 57, 17, 33, 164, 150, 46, 103, 176, 160,
+ 156, 187, 233, 166, 223, 163, 253, 147, 235, 95,
+ 184, 83, 245, 146, 101, 198, 247, 34, 198, 191,
+ 11, 16, 94, 237, 216, 20, 175]);
+ result = alg.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption);
+ expected = new Uint8Array([
+ 42, 218, 213, 39, 73, 91, 72, 79, 67, 38, 248,
+ 133, 18, 189, 61, 34, 107, 79, 29, 56, 59,
+ 181, 213, 118, 113, 34, 65, 210, 87, 174, 22,
+ 239]);
+ expect(result).toEqual(expected);
+ });
+ });
});
+
+
describe('CipherTransformFactory', function() {
function DictMock(map) {
this.map = map;
@@ -222,9 +524,136 @@ describe('CipherTransformFactory', function() {
P: -1084,
R: 4
};
+
+ var aes256Map = {
+ Filter: Name.get('Standard'),
+ V: 5,
+ Length: 256,
+ O: unescape('%3Cb%89%233e%C8%98%D2%B2%E2%E4%86%CD%A3%18%CC%7E%B1%24j2%24%' +
+ '7D%D2%AC%ABx%DEl%8Bs%F3vG%99%80%11e%3E%C8%F5%F2%0C%DA%7B%18x'),
+ U: unescape('%83%F2%8F%A0W%02%8A%86O%FD%BD%AD%E0I%90%F1%BEQ%C5%0F%F9i%91%' +
+ '97%0F%C2A%03%01%7E%BB%DDu%A9%04%20%9Fe%16%DC%A8%5E%D7%C0d%26' +
+ '%BC%28'),
+ OE: unescape('%D5%CA%0E%BDnLF%BF%06%C3%0A%BE%9Dd%90U%08%3E%7B%B2%9C%E52%2' +
+ '8%E5%D86%DE%22%26j%DF'),
+ UE: unescape('%23%96%C3%A9%F533%FF%9E%9E%21%F2%E7K%7D%BE%19%7E%ACr%C3%F4%' +
+ '89%F5%EA%A5*J%3C%26%11%11'),
+ Perms: unescape('%D8%FC%844%E5e%0DB%5D%7Ff%FD%3COMM'),
+ P: -1084,
+ R: 5
+ };
+
+ var aes256IsoMap = {
+ Filter: Name.get('Standard'),
+ V: 5,
+ Length: 256,
+ O: unescape('X%E8%3E6%F5%1A%F5%D1%89%7B%DDH%C71%25%D9%1FJs%A7%7F%9E%B0M-%' +
+ 'A3W/%27Z%D9%8D%8E%E8%A9%D0%CA%D6%05%B9%1D%D0%B9.%0BL%87%95'),
+ U: unescape('%5E%E6%CDK%A6c%FAL%DB%80%11U9%11%21%A4%96.g%B0%A0%9C%BB%E9%A' +
+ '6%DF%A3%FD%93%EB_%B8S%F5%92e%C6%F7%22%C6%BF%0B%10%5E%ED%D8%1' +
+ '4%AF'),
+ OE: unescape('%D1I%E0Mg%9B%C9%B5%BED%DF%14%3EZ8%D2%05%F0%B2%80%EE%7CD%FE%' +
+ 'FD%F4%3El%D0%87%0A%FB'),
+ UE: unescape('y%D0%02%B5%E6Y%9C%3C%FD%8F%D4%1CT%B4%C4%B1%AD%80%DDk.%14%5E' +
+ '%BA%873_%18%14%DF%FE%24'),
+ Perms: unescape('l%AD%0F%A0%EBM%86WM%3E%CB%B5%E0X%C97'),
+ P: -1084,
+ R: 6
+ };
+
+ var aes256BlankMap = {
+ Filter: Name.get('Standard'),
+ V: 5,
+ Length: 256,
+ O: unescape('%B8p%04%C3g%26%FCW%CCN%D4%16%A1%E8%950YZ%C9%9E%B1-%97%F3%FE%' +
+ '03%13%19ffZn%8F%F5%EB%EC%CC5sV%10e%CEl%B5%E9G%C1'),
+ U: unescape('%83%D4zi%F1O0%961%12%CC%82%CB%CA%BF5y%FD%21%EB%E4%D1%B5%1D%D' +
+ '6%FA%14%F3%BE%8Fqs%EF%88%DE%E2%E8%DC%F55%E4%B8%16%C8%14%8De%' +
+ '1E'),
+ OE: unescape('%8F%19%E8%D4%27%D5%07%CA%C6%A1%11%A6a%5Bt%F4%DF%0F%84%29%0F' +
+ '%E4%EFF7%5B%5B%11%A0%8F%17e'),
+ UE: unescape('%81%F5%5D%B0%28%81%E4%7F_%7C%8F%85b%A0%7E%10%D0%88lx%7B%7EJ' +
+ '%5E%912%B6d%12%27%05%F6'),
+ Perms: unescape('%86%1562%0D%AE%A2%FB%5D%3B%22%3Dq%12%B2H'),
+ P: -1084,
+ R: 5
+ };
+
+ var aes256IBlankMap = {
+ Filter: Name.get('Standard'),
+ V: 5,
+ Length: 256,
+ O: unescape('%F7%DB%99U%A6M%ACk%AF%CF%D7AFw%E9%C1%91%CBDgI%23R%CF%0C%15r%' +
+ 'D74%0D%CE%E9%91@%E4%98QF%BF%88%7Ej%DE%AD%8F%F4@%C1'),
+ U: unescape('%1A%A9%DC%918%83%93k%29%5B%117%B16%DB%E8%8E%FE%28%E5%89%D4%0' +
+ 'E%AD%12%3B%7DN_6fez%8BG%18%05YOh%7DZH%A3Z%87%17*'),
+ OE: unescape('%A4a%88%20h%1B%7F%CD%D5%CAc%D8R%83%E5%D6%1C%D2%98%07%984%BA' +
+ '%AF%1B%B4%7FQ%F8%1EU%7D'),
+ UE: unescape('%A0%0AZU%27%1D%27%2C%0B%FE%0E%A2L%F9b%5E%A1%B9%D6v7b%B26%A9' +
+ 'N%99%F1%A4Deq'),
+ Perms: unescape('%03%F2i%07%0D%C3%F9%F2%28%80%B7%F5%DD%D1c%EB'),
+ P: -1084,
+ R: 6
+ };
+
var fileID2 = unescape('%3CL_%3AD%96%AF@%9A%9D%B3%3Cx%1Cv%AC');
describe('#ctor', function() {
+ describe('AES256 Revision 5', function () {
+ it('should accept user password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256Map),
+ fileID1,
+ 'user');
+ });
+ it('should accept owner password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256Map),
+ fileID1,
+ 'owner');
+ });
+ it('should not accept wrong password', function () {
+ var thrown = false;
+ try {
+ var factory = new CipherTransformFactory(new DictMock(aes256Map),
+ fileID1,
+ 'wrong');
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).toEqual(true);
+ });
+ it('should accept blank password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256BlankMap),
+ fileID1);
+ });
+ });
+
+ describe('AES256 Revision 6', function () {
+ it('should accept user password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256IsoMap),
+ fileID1,
+ 'user');
+ });
+ it('should accept owner password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256IsoMap),
+ fileID1,
+ 'owner');
+ });
+ it('should not accept wrong password', function () {
+ var thrown = false;
+ try {
+ var factory = new CipherTransformFactory(new DictMock(aes256IsoMap),
+ fileID1,
+ 'wrong');
+ } catch (e) {
+ thrown = true;
+ }
+ expect(thrown).toEqual(true);
+ });
+ it('should accept blank password', function () {
+ var factory = new CipherTransformFactory(new DictMock(aes256IBlankMap),
+ fileID1);
+ });
+ });
it('should accept user password', function() {
var factory = new CipherTransformFactory(new DictMock(map1), fileID1,
'123456');
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git
More information about the Pkg-javascript-commits
mailing list