UNPKG

@syncfusion/ej2-pdf

Version:

Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.

411 lines (410 loc) 17.9 kB
import { _isName, _PdfName } from './../pdf-primitives'; import { FormatError, _stringToBytes, _areArrayEqual } from './../utils'; import { _MD5 } from './encryptors/messageDigest5'; import { _AdvancedEncryption, _BasicEncryption } from './encryptors/basic-encryption'; import { _NormalCipherFour, _NullCipher } from './encryptors/normal-cipher'; import { _CipherTransform } from './encryptors/cipher-tranform'; import { _AdvancedEncryption128Cipher, _AdvancedEncryption256Cipher } from './encryptors/advance-cipher'; var _PdfEncryptor = /** @class */ (function () { function _PdfEncryptor(dictionary, id, password) { this._isUserPassword = true; this._hasUserPasswordOnly = false; this._encryptOnlyAttachment = false; this._encryptMetaData = true; this._defaultPasswordBytes = new Uint8Array([0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a]); if (password === null || typeof password === 'undefined') { password = ''; } var filter = dictionary.get('Filter'); if (!_isName(filter, 'Standard')) { throw new FormatError('unknown encryption method'); } this._filterName = filter.name; this._dictionary = dictionary; var algorithm = dictionary.get('V'); if (!Number.isInteger(algorithm) || (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5)) { throw new FormatError('unsupported encryption algorithm'); } this._algorithm = algorithm; var keyLength = dictionary.get('Length'); if (!keyLength) { if (algorithm <= 3) { keyLength = 40; } else { var cfDictionary = dictionary.get('CF'); var streamCryptoName = dictionary.get('StmF'); if (cfDictionary && streamCryptoName) { cfDictionary.suppressEncryption = true; var handlerDictionary = cfDictionary.get(streamCryptoName.name); keyLength = (handlerDictionary && handlerDictionary.get('Length')) || 128; if (keyLength < 40) { keyLength <<= 3; } } } } if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) { throw new FormatError('invalid key length'); } var ownerPassword = _stringToBytes(dictionary.get('O'), false, true).subarray(0, 32); var userPassword = _stringToBytes(dictionary.get('U'), false, true).subarray(0, 32); var flag = dictionary.get('P'); var revision = dictionary.get('R'); this._encryptMetaData = (algorithm === 4 || algorithm === 5) && dictionary.get('EncryptMetadata') !== false; var fileIdBytes = _stringToBytes(id, false, true); var passwordBytes; if (password) { passwordBytes = _stringToBytes(password, false, true); } var encryptionKey; if (algorithm !== 5) { encryptionKey = this._prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flag, revision, keyLength, this._encryptMetaData); if (encryptionKey) { this._isUserPassword = true; if (password) { var decodedPassword = this._decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength); var ownerEncryptionKey = this._prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flag, revision, keyLength, this._encryptMetaData); if (ownerEncryptionKey && _areArrayEqual(ownerEncryptionKey, encryptionKey)) { this._hasUserPasswordOnly = true; } } } } else { var ownerValidationKey = _stringToBytes(dictionary.get('O'), false, true); var ownerValidationSalt = ownerValidationKey.subarray(32, 40); var ownerKeySalt = ownerValidationKey.subarray(40, 48); var userValidationKey = _stringToBytes(dictionary.get('U'), false, true); var uBytes = userValidationKey.subarray(0, 48); var userValidationSalt = userValidationKey.subarray(32, 40); var userKeySalt = userValidationKey.subarray(40, 48); var ownerEncryption = _stringToBytes(dictionary.get('OE'), false, true); var userEncryption = _stringToBytes(dictionary.get('UE'), false, true); var algorithm_1; if (revision === 6) { algorithm_1 = new _AdvancedEncryption(); } else { algorithm_1 = new _BasicEncryption(); } var p = void 0; if (passwordBytes) { p = passwordBytes.subarray(0, Math.min(127, passwordBytes.length)); } else { p = new Uint8Array([]); } if (algorithm_1._checkUserPassword(p, userValidationSalt, userPassword)) { encryptionKey = this._createEncryptionKey(true, p, ownerKeySalt, uBytes, userKeySalt, ownerEncryption, userEncryption, algorithm_1); this._isUserPassword = true; if (password.length && algorithm_1._checkOwnerPassword(p, ownerValidationSalt, uBytes, ownerPassword)) { this._hasUserPasswordOnly = true; } } else if (password.length && algorithm_1._checkOwnerPassword(p, ownerValidationSalt, uBytes, ownerPassword)) { encryptionKey = this._createEncryptionKey(false, passwordBytes, ownerKeySalt, uBytes, userKeySalt, ownerEncryption, userEncryption, algorithm_1); this._isUserPassword = false; } } if (!encryptionKey) { if (password) { var decodedPassword = this._decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength); encryptionKey = this._prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flag, revision, keyLength, this._encryptMetaData); this._isUserPassword = false; } else { throw new Error('Cannot open an encrypted document. The password is invalid.'); } } if (algorithm >= 4) { var cipherDictionary = dictionary.get('CF'); if (cipherDictionary) { cipherDictionary.suppressEncryption = true; if (cipherDictionary.has('StdCF')) { var standardCryptFilter = cipherDictionary.get('StdCF'); if (standardCryptFilter && standardCryptFilter.has('AuthEvent')) { var event_1 = standardCryptFilter.get('AuthEvent'); if (event_1 && event_1.name === 'EFOpen') { this._encryptOnlyAttachment = true; } } } } this._cipherDictionary = cipherDictionary; this._stream = dictionary.get('StmF') || _PdfName.get('Identity'); this._string = dictionary.get('StrF') || _PdfName.get('Identity'); this._eff = dictionary.get('EFF') || this._stream; } if (!encryptionKey && !this._encryptOnlyAttachment) { throw new Error('Cannot open an encrypted document. The password is invalid.'); } this._encryptionKey = encryptionKey; } Object.defineProperty(_PdfEncryptor.prototype, "_md5", { get: function () { if (typeof this._messageDigest === 'undefined' || this._messageDigest === null) { this._messageDigest = new _MD5(); } return this._messageDigest; }, enumerable: true, configurable: true }); _PdfEncryptor.prototype._createEncryptionKey = function (isUserKey, password, ownerKeySalt, uBytes, userKeySalt, ownerEncryption, userEncryption, algorithm) { if (isUserKey) { return algorithm._getUserKey(password, userKeySalt, userEncryption); } else { return algorithm._getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption); } }; _PdfEncryptor.prototype._prepareKeyData = function (id, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetaData) { var hashData = new Uint8Array(40 + ownerPassword.length + id.length); var i = 0; var j = 0; var n; if (password) { n = Math.min(32, password.length); for (; i < n; ++i) { hashData[i] = password[i]; } } while (i < 32) { hashData[i++] = this._defaultPasswordBytes[j++]; } for (j = 0, n = ownerPassword.length; j < n; ++j) { hashData[i++] = ownerPassword[j]; } hashData[i++] = flags & 0xff; hashData[i++] = (flags >> 8) & 0xff; hashData[i++] = (flags >> 16) & 0xff; hashData[i++] = (flags >>> 24) & 0xff; for (j = 0, n = id.length; j < n; ++j) { hashData[i++] = id[j]; } if (revision >= 4 && !encryptMetaData) { hashData[i++] = 0xff; hashData[i++] = 0xff; hashData[i++] = 0xff; hashData[i++] = 0xff; } var hash = this._md5.hash(hashData, 0, i); var keyLengthInBytes = keyLength >> 3; if (revision >= 3) { for (j = 0; j < 50; ++j) { hash = this._md5.hash(hash, 0, keyLengthInBytes); } } var encryptionKey = hash.subarray(0, keyLengthInBytes); var cipher; var checkData; if (revision >= 3) { for (i = 0; i < 32; ++i) { hashData[i] = this._defaultPasswordBytes[i]; } for (j = 0, n = id.length; j < n; ++j) { hashData[i++] = id[j]; } cipher = new _NormalCipherFour(encryptionKey); checkData = cipher._encryptBlock(this._md5.hash(hashData, 0, i)); n = encryptionKey.length; var derivedKey = new Uint8Array(n); for (j = 1; j <= 19; ++j) { for (var k = 0; k < n; ++k) { derivedKey[k] = encryptionKey[k] ^ j; } cipher = new _NormalCipherFour(derivedKey); checkData = cipher._encryptBlock(checkData); } for (j = 0, n = checkData.length; j < n; ++j) { if (userPassword[j] !== checkData[j]) { return null; } } } else { cipher = new _NormalCipherFour(encryptionKey); checkData = cipher._encryptBlock(this._defaultPasswordBytes); for (j = 0, n = checkData.length; j < n; ++j) { if (userPassword[j] !== checkData[j]) { return null; } } } return encryptionKey; }; _PdfEncryptor.prototype._decodeUserPassword = function (password, ownerPassword, revision, keyLength) { var hashData = new Uint8Array(32); var i = 0; var j = 0; var n = Math.min(32, password.length); for (; i < n; ++i) { hashData[i] = password[i]; } while (i < 32) { hashData[i++] = this._defaultPasswordBytes[j++]; } var hash = this._md5.hash(hashData, 0, i); var keyLengthInBytes = keyLength >> 3; if (revision >= 3) { for (j = 0; j < 50; ++j) { hash = this._md5.hash(hash, 0, hash.length); } } var cipher; var userPassword; if (revision >= 3) { userPassword = ownerPassword; var derivedKey = new Uint8Array(keyLengthInBytes); for (j = 19; j >= 0; j--) { for (var k = 0; k < keyLengthInBytes; ++k) { derivedKey[k] = hash[k] ^ j; } cipher = new _NormalCipherFour(derivedKey); userPassword = cipher._encryptBlock(userPassword); } } else { cipher = new _NormalCipherFour(hash.subarray(0, keyLengthInBytes)); userPassword = cipher._encryptBlock(ownerPassword); } return userPassword; }; _PdfEncryptor.prototype._createCipherTransform = function (objectNumber, generationNumber) { if (this._algorithm === 4 || this._algorithm === 5) { var stringCipher = this._buildCipherConstructor(this._cipherDictionary, this._string, objectNumber, generationNumber, this._encryptionKey); var streamCipher = this._buildCipherConstructor(this._cipherDictionary, this._stream, objectNumber, generationNumber, this._encryptionKey); return new _CipherTransform(stringCipher, streamCipher); } var key = this._buildObjectKey(objectNumber, generationNumber, this._encryptionKey, false); return new _CipherTransform(new _NormalCipherFour(key), new _NormalCipherFour(key)); }; _PdfEncryptor.prototype._buildCipherConstructor = function (cipherDictionary, name, objectNumber, generationNumber, key) { var cryptFilter = cipherDictionary.get(name.name); var cfm; if (cryptFilter) { cfm = cryptFilter.get('CFM'); } if (!cfm) { return new _NullCipher(); } switch (cfm.name) { case 'None': return new _NullCipher(); case 'AESV2': return new _AdvancedEncryption128Cipher(this._buildObjectKey(objectNumber, generationNumber, key, true)); case 'AESV3': return new _AdvancedEncryption256Cipher(key); case 'V2': return new _NormalCipherFour(this._buildObjectKey(objectNumber, generationNumber, key, false)); } throw new FormatError('Unknown cryptography method'); }; _PdfEncryptor.prototype._buildObjectKey = function (objectNumber, generationNumber, encryptionKey, isAdvancedEncryption) { if (isAdvancedEncryption === void 0) { isAdvancedEncryption = false; } var key = new Uint8Array(encryptionKey.length + 9); var i; for (i = 0; i < encryptionKey.length; ++i) { key[i] = encryptionKey[i]; } key[i++] = objectNumber & 0xff; key[i++] = (objectNumber >> 8) & 0xff; key[i++] = (objectNumber >> 16) & 0xff; key[i++] = generationNumber & 0xff; key[i++] = (generationNumber >> 8) & 0xff; if (isAdvancedEncryption) { key[i++] = 0x73; key[i++] = 0x41; key[i++] = 0x6c; key[i++] = 0x54; } var hash = this._md5.hash(key, 0, i); return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); }; return _PdfEncryptor; }()); export { _PdfEncryptor }; var _Word64 = /** @class */ (function () { function _Word64(high, low) { this.high = high | 0; this.low = low | 0; } _Word64.prototype.and = function (word) { this.high &= word.high; this.low &= word.low; }; _Word64.prototype.or = function (word) { this.high |= word.high; this.low |= word.low; }; _Word64.prototype.not = function () { this.high = ~this.high; this.low = ~this.low; }; _Word64.prototype.xor = function (word) { this.high ^= word.high; this.low ^= word.low; }; _Word64.prototype.shiftRight = function (places) { if (places >= 32) { this.low = (this.high >>> (places - 32)) | 0; this.high = 0; } else { this.low = (this.low >>> places) | (this.high << (32 - places)); this.high = (this.high >>> places) | 0; } }; _Word64.prototype.shiftLeft = function (places) { if (places >= 32) { this.high = this.low << (places - 32); this.low = 0; } else { this.high = (this.high << places) | (this.low >>> (32 - places)); this.low <<= places; } }; _Word64.prototype.rotateRight = function (places) { var low; var high; if (places & 32) { high = this.low; low = this.high; } else { low = this.low; high = this.high; } places &= 31; this.low = (low >>> places) | (high << (32 - places)); this.high = (high >>> places) | (low << (32 - places)); }; _Word64.prototype.add = function (word) { var lowAdd = (this.low >>> 0) + (word.low >>> 0); var highAdd = (this.high >>> 0) + (word.high >>> 0); if (lowAdd > 0xffffffff) { highAdd += 1; } this.low = lowAdd | 0; this.high = highAdd | 0; }; _Word64.prototype.copyTo = function (bytes, offset) { 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; }; _Word64.prototype.assign = function (word) { this.high = word.high; this.low = word.low; }; return _Word64; }()); export { _Word64 };