UNPKG

@digital-blueprint/annotpdf

Version:

Javascript library for creating annotations in PDF documents

186 lines 8.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const util_1 = require("./util"); const crypto_util_1 = require("./crypto-util"); exports.RC4_40_BIT = true; class IdentityEngine { encrypt(data, reference) { return data; } decrypt(data, reference) { return data; } isUserPasswordCorrect() { return true; } isOwnerPasswordCorrect() { return true; } } exports.IdentityEngine = IdentityEngine; class RC4CryptoEngine { constructor(cryptoConfiguration, file_id, rc4_40_bit = false) { this.cryptoConfiguration = cryptoConfiguration; this.file_id = file_id; this.rc4_40_bit = rc4_40_bit; this.encryptionKey = undefined; this.computed_user_password = undefined; this.computed_owner_password = undefined; } encrypt(data, reference) { if (!reference) throw Error("Undefined reference pointer of encrypted object"); let encryptionKey = this.computeEncryptionKey(); let adapted_key = new Uint8Array(encryptionKey.length + 5); adapted_key.set(encryptionKey, 0); let obj = crypto_util_1.CryptoUtil.convertNumberToLittleEndianByteArray(reference.obj); adapted_key.set(obj.slice(0, 3), encryptionKey.length); let gen = crypto_util_1.CryptoUtil.convertNumberToLittleEndianByteArray(reference.generation); adapted_key.set(gen.slice(0, 2), encryptionKey.length + 3); let key_hash = crypto_util_1.CryptoUtil.MD5AsByteArray(adapted_key); let encrypted = crypto_util_1.CryptoUtil.RC4(data, key_hash.slice(0, Math.min(encryptionKey.length + 5, 16))); return crypto_util_1.CryptoUtil.convertWordArrayToByteArray(encrypted); } decrypt(data, reference) { return this.encrypt(data, reference); } /** * Computes the RC4 encryption key * */ computeEncryptionKey() { if (this.encryptionKey) return this.encryptionKey; let userpwd = crypto_util_1.CryptoUtil.padPasswortString(this.cryptoConfiguration.user_pwd); if (!this.cryptoConfiguration.owner_pwd_c) throw Error("Invalid /O value (owner password)"); let oValue = this.cryptoConfiguration.owner_pwd_c; if (oValue.length !== 32) throw Error(`Invalid length of owner value. Is ${oValue.length} but must be 32.`); if (!this.cryptoConfiguration.permissions) throw Error("Permissions not set"); let permissions = crypto_util_1.CryptoUtil.convertNumberToLittleEndianByteArray(this.cryptoConfiguration.permissions); if (!this.file_id || this.file_id.length === 0) throw Error("File ID not set"); let keylength = 40; if (this.cryptoConfiguration.length) keylength = this.cryptoConfiguration.length; let file_id = this.file_id[0]; let stuff = new Uint8Array(userpwd.length + oValue.length + permissions.length + file_id.length); stuff.set(userpwd, 0); stuff.set(oValue, userpwd.length); stuff.set(permissions, userpwd.length + oValue.length); stuff.set(file_id, userpwd.length + oValue.length + permissions.length); let h = crypto_util_1.CryptoUtil.MD5AsByteArray(stuff); keylength = keylength >> 3; if (this.cryptoConfiguration.revision && this.cryptoConfiguration.revision >= 3) { for (let i = 0; i < 50; ++i) { h = crypto_util_1.CryptoUtil.MD5AsByteArray(h.slice(0, keylength)); } } if (this.rc4_40_bit) { this.encryptionKey = h.slice(0, 5); } else { this.encryptionKey = h; } return this.encryptionKey; } /** * Derives the user password (/U) value * */ computeUserPassword() { if (this.computed_user_password) return this.computed_user_password; if (this.cryptoConfiguration.revision && this.cryptoConfiguration.revision >= 3) { return this.computeUserPasswordRevision3OrGreater(); } else if (this.cryptoConfiguration.revision === 2) { return this.computeUserPasswordRevision2(); } return new Uint8Array([]); } /** * Computes the user password for security handlers of revision 2 * */ computeUserPasswordRevision2() { let padding_str = new Uint8Array(crypto_util_1.CryptoUtil.PADDING_STRING); let enc_key = this.computeEncryptionKey(); let x = crypto_util_1.CryptoUtil.RC4(padding_str, enc_key); this.computed_user_password = crypto_util_1.CryptoUtil.convertWordArrayToByteArray(x); return this.computed_user_password; } /** * Computes the user password for security handlers of revision 3 or higher * */ computeUserPasswordRevision3OrGreater() { if (!this.file_id) throw Error("No file id"); let id_str_array = this.file_id[0]; let new_val = new Uint8Array(crypto_util_1.CryptoUtil.PADDING_STRING.length + id_str_array.length); new_val.set(crypto_util_1.CryptoUtil.PADDING_STRING, 0); new_val.set(id_str_array, crypto_util_1.CryptoUtil.PADDING_STRING.length); let x = crypto_util_1.CryptoUtil.MD5(new_val); let enc_key = this.computeEncryptionKey(); for (let i = 0; i < 20; ++i) { x = crypto_util_1.CryptoUtil.RC4(x, crypto_util_1.CryptoUtil.xorBytes(enc_key, i)); } this.computed_user_password = crypto_util_1.CryptoUtil.convertWordArrayToByteArray(x); return this.computed_user_password; } /** * Derives the owner password (/O) value **/ computeOwnerPassword() { if (this.computed_owner_password) return this.computed_owner_password; let pwd_string = this.cryptoConfiguration.owner_pwd; // if no owner password is set, but a user password use this if (!this.cryptoConfiguration.owner_pwd || this.cryptoConfiguration.owner_pwd === "") pwd_string = this.cryptoConfiguration.user_pwd; let ownerpwd = crypto_util_1.CryptoUtil.padPasswortString(pwd_string); let h = crypto_util_1.CryptoUtil.MD5(ownerpwd); let count = 1; if (this.cryptoConfiguration.revision && this.cryptoConfiguration.revision >= 3) { count = 20; for (let i = 0; i < 50; ++i) { h = crypto_util_1.CryptoUtil.MD5(h); } } let length = 128; if (this.cryptoConfiguration.length) length = this.cryptoConfiguration.length; let enc_key = crypto_util_1.CryptoUtil.convertWordArrayToByteArray(h).slice(0, length / 8); let userpwd = crypto_util_1.CryptoUtil.padPasswortString(this.cryptoConfiguration.user_pwd); let x = crypto_util_1.CryptoUtil.convertToWordArray(userpwd); for (let i = 0; i < count; ++i) { x = crypto_util_1.CryptoUtil.RC4(x, crypto_util_1.CryptoUtil.xorBytes(enc_key, i)); } this.computed_owner_password = crypto_util_1.CryptoUtil.convertWordArrayToByteArray(x); return this.computed_owner_password; } /** * Returns true if the provided password corresponds to the defined /U value * */ isUserPasswordCorrect() { let user_pwd = this.computeUserPassword(); if (!this.cryptoConfiguration.user_pwd_c) throw Error("Invalid /U value (user password)"); if (this.cryptoConfiguration.revision && this.cryptoConfiguration.revision >= 3) { return util_1.Util.areArraysEqual(user_pwd, this.cryptoConfiguration.user_pwd_c.slice(0, 16)); } else { return util_1.Util.areArraysEqual(user_pwd, this.cryptoConfiguration.user_pwd_c); } } /** * Returns true if the provided password corresponds to the defined /O value * */ isOwnerPasswordCorrect() { let owner_pwd = this.computeOwnerPassword(); if (!this.cryptoConfiguration.owner_pwd_c) throw Error("Invalid /O value (owner password)"); return util_1.Util.areArraysEqual(owner_pwd, this.cryptoConfiguration.owner_pwd_c); } } exports.RC4CryptoEngine = RC4CryptoEngine; //# sourceMappingURL=crypto.js.map