diff options
author | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
commit | ad547a6b5986815fda458221149728d9d9ab1d87 (patch) | |
tree | 16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/dvipdfm-x/pdfencrypt.c | |
parent | 947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff) |
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/pdfencrypt.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/pdfencrypt.c | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/pdfencrypt.c b/Build/source/texk/dvipdfm-x/pdfencrypt.c new file mode 100644 index 00000000000..524181b084f --- /dev/null +++ b/Build/source/texk/dvipdfm-x/pdfencrypt.c @@ -0,0 +1,764 @@ +/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "system.h" +#include "mem.h" +#include "numbers.h" +#include "error.h" +#include "dpxconf.h" +#include "dpxutil.h" + +#include "pdfobj.h" +#include "unicode.h" +#include "dpxcrypt.h" + +/* Encryption support + * + * Supported: 40-128 bit RC4, 128 bit AES, 256 bit AES + * + * TODO: Convert password to PDFDocEncoding. SASLPrep stringpref for AESV3. + */ + + +#define USE_ADOBE_EXTENSION 1 + +#include "dvipdfmx.h" +#include "pdfencrypt.h" + +struct pdf_sec { + unsigned char key[32]; + int key_size; + + unsigned char ID[16]; + unsigned char O[48], U[48]; + unsigned char OE[32], UE[32]; + int V, R; + int32_t P; + + struct { + int use_aes; + int encrypt_metadata; + int need_adobe_extension; + } setting; + + struct { + uint64_t objnum; + uint16_t gennum; + } label; +}; + +static void pdf_enc_set_password (pdf_sec *p_sec, unsigned int bits, unsigned int perm, + const char *oplain, const char *uplain); + +static const unsigned char padding_bytes[32] = { + 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 +}; + +pdf_sec * +pdf_enc_init (const unsigned char *id, + int keybits, uint32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata) +{ + time_t current_time; + pdf_sec *p_sec; + + p_sec = NEW(1, pdf_sec); + memset(p_sec, 0, sizeof(pdf_sec)); + current_time = dpx_util_get_unique_time_if_given(); + if (current_time == INVALID_EPOCH_VALUE) + current_time = time(NULL); + srand(current_time); /* For AES IV */ + p_sec->setting.use_aes = use_aes; + p_sec->setting.encrypt_metadata = encrypt_metadata; + p_sec->setting.need_adobe_extension = 0; + + memcpy(p_sec->ID, id, 16); + pdf_enc_set_password(p_sec, keybits, permission, opasswd, upasswd); + + return p_sec; +} + +void +pdf_enc_close (pdf_sec **p_sec) +{ + if (p_sec && *p_sec) { + RELEASE(*p_sec); + *p_sec = NULL; + } +} + +static void +passwd_padding (const char *src, unsigned char *dst) +{ + int len; + + len = MIN(32, strlen(src)); + + memcpy(dst, src, len); + memcpy(dst + len, padding_bytes, 32 - len); +} + +static void +compute_owner_password (pdf_sec *p_sec, + const char *opasswd, const char *upasswd) +{ + int i, j; + unsigned char padded[32]; + MD5_CONTEXT md5; + ARC4_CONTEXT arc4; + unsigned char hash[16]; + + passwd_padding((strlen(opasswd) > 0 ? opasswd : upasswd), padded); + + MD5_init (&md5); + MD5_write(&md5, padded, 32); + MD5_final(hash, &md5); + if (p_sec->R >= 3) { + for (i = 0; i < 50; i++) { + /* + * NOTE: We truncate each MD5 hash as in the following step. + * Otherwise Adobe Reader won't decrypt the PDF file. + */ + MD5_init (&md5); + MD5_write(&md5, hash, p_sec->key_size); + MD5_final(hash, &md5); + } + } + ARC4_set_key(&arc4, p_sec->key_size, hash); + passwd_padding(upasswd, padded); + { + unsigned char tmp1[32], tmp2[32]; + unsigned char key[16]; + + ARC4(&arc4, 32, padded, tmp1); + if (p_sec->R >= 3) { + for (i = 1; i <= 19; i++) { + memcpy(tmp2, tmp1, 32); + for (j = 0; j < p_sec->key_size; j++) + key[j] = hash[j] ^ i; + ARC4_set_key(&arc4, p_sec->key_size, key); + ARC4(&arc4, 32, tmp2, tmp1); + } + } + memcpy(p_sec->O, tmp1, 32); + } +} + +static void +compute_encryption_key (pdf_sec *p_sec, const char *passwd) +{ + int i; + unsigned char hash[32], padded[32]; + MD5_CONTEXT md5; + + passwd_padding(passwd, padded); + MD5_init (&md5); + MD5_write(&md5, padded, 32); + MD5_write(&md5, p_sec->O, 32); + { + unsigned char tmp[4]; + + tmp[0] = (unsigned char)(p_sec->P) & 0xFF; + tmp[1] = (unsigned char)(p_sec->P >> 8) & 0xFF; + tmp[2] = (unsigned char)(p_sec->P >> 16) & 0xFF; + tmp[3] = (unsigned char)(p_sec->P >> 24) & 0xFF; + MD5_write(&md5, tmp, 4); + } + MD5_write(&md5, p_sec->ID, 16); +#if 0 + /* Not Supported Yet */ + if (!p_sec->setting.encrypt_metadata) { + unsigned char tmp[4] = {0xff, 0xff, 0xff, 0xff}; + MD5_write(&md5, tmp, 4); + } +#endif + MD5_final(hash, &md5); + + if (p_sec->R >= 3) { + for (i = 0; i < 50; i++) { + /* + * NOTE: We truncate each MD5 hash as in the following step. + * Otherwise Adobe Reader won't decrypt the PDF file. + */ + MD5_init (&md5); + MD5_write(&md5, hash, p_sec->key_size); + MD5_final(hash, &md5); + } + } + memcpy(p_sec->key, hash, p_sec->key_size); +} + +static void +compute_user_password (pdf_sec *p_sec, const char *uplain) +{ + int i, j; + ARC4_CONTEXT arc4; + MD5_CONTEXT md5; + unsigned char upasswd[32]; + + compute_encryption_key(p_sec, uplain); + + switch (p_sec->R) { + case 2: + ARC4_set_key(&arc4, p_sec->key_size, p_sec->key); + ARC4(&arc4, 32, padding_bytes, upasswd); + break; + case 3: case 4: + { + unsigned char hash[32]; + unsigned char tmp1[32], tmp2[32]; + + MD5_init (&md5); + MD5_write(&md5, padding_bytes, 32); + + MD5_write(&md5, p_sec->ID, 16); + MD5_final(hash, &md5); + + ARC4_set_key(&arc4, p_sec->key_size, p_sec->key); + ARC4(&arc4, 16, hash, tmp1); + + for (i = 1; i <= 19; i++) { + unsigned char key[16]; + + memcpy(tmp2, tmp1, 16); + for (j = 0; j < p_sec->key_size; j++) + key[j] = p_sec->key[j] ^ i; + ARC4_set_key(&arc4, p_sec->key_size, key); + ARC4(&arc4, 16, tmp2, tmp1); + } + memcpy(upasswd, tmp1, 32); + } + break; + default: + ERROR("Invalid revision number."); + } + + memcpy(p_sec->U, upasswd, 32); +} + +/* Algorithm 2.B from ISO 32000-1 chapter 7 */ +static void +compute_hash_V5 (unsigned char *hash, + const char *passwd, + const unsigned char *salt, + const unsigned char *user_key, int R /* revision */) +{ + unsigned char K[64]; + size_t K_len; + int nround; + + { + SHA256_CONTEXT sha; + + SHA256_init (&sha); + SHA256_write(&sha, (const unsigned char *)passwd, strlen(passwd)); + SHA256_write(&sha, salt, 8); + if (user_key) + SHA256_write(&sha, user_key, 48); + SHA256_final(hash, &sha); + } + + ASSERT( R ==5 || R == 6 ); + + if (R == 5) + return; + + memcpy(K, hash, 32); K_len = 32; + for (nround = 1; ; nround++) { /* Initial K count as nround 0. */ + unsigned char K1[256], *Kr, *E; + size_t K1_len, E_len; + int i, c, E_mod3 = 0; + + K1_len = strlen(passwd) + K_len + (user_key ? 48 : 0); + ASSERT(K1_len < 240); + memcpy(K1, passwd, strlen(passwd)); + memcpy(K1 + strlen(passwd), K, K_len); + if (user_key) + memcpy(K1 + strlen(passwd) + K_len, user_key, 48); + + Kr = NEW(K1_len * 64, unsigned char); + for (i = 0; i < 64; i++) + memcpy(Kr + i * K1_len, K1, K1_len); + AES_cbc_encrypt(K, 16, K + 16, 0, Kr, K1_len * 64, &E, &E_len); + RELEASE(Kr); + + for (i = 0; i < 16; i++) + E_mod3 += E[i]; + E_mod3 %= 3; + + switch (E_mod3) { + case 0: + { + SHA256_CONTEXT sha; + + SHA256_init (&sha); + SHA256_write(&sha, E, E_len); + SHA256_final(K, &sha); + K_len = 32; + } + break; + case 1: + { + SHA512_CONTEXT sha; + + SHA384_init (&sha); + SHA384_write(&sha, E, E_len); + SHA384_final(K, &sha); + K_len = 48; + } + break; + case 2: + { + SHA512_CONTEXT sha; + + SHA512_init (&sha); + SHA512_write(&sha, E, E_len); + SHA512_final(K, &sha); + K_len = 64; + } + break; + } + c = (uint8_t) E[E_len - 1]; + RELEASE(E); + if (nround >= 64 && c <= nround - 32) + break; + } + memcpy(hash, K, 32); +} + +static void +compute_owner_password_V5 (pdf_sec *p_sec, const char *oplain) +{ + unsigned char vsalt[8], ksalt[8], hash[32]; + unsigned char *OE, iv[AES_BLOCKSIZE]; + size_t OE_len; + int i; + + for (i = 0; i < 8 ; i++) { + vsalt[i] = rand() % 256; + ksalt[i] = rand() % 256; + } + + compute_hash_V5(hash, oplain, vsalt, p_sec->U, p_sec->R); + memcpy(p_sec->O, hash, 32); + memcpy(p_sec->O + 32, vsalt, 8); + memcpy(p_sec->O + 40, ksalt, 8); + + compute_hash_V5(hash, oplain, ksalt, p_sec->U, p_sec->R); + memset(iv, 0, AES_BLOCKSIZE); + AES_cbc_encrypt(hash, 32, iv, 0, p_sec->key, p_sec->key_size, &OE, &OE_len); + memcpy(p_sec->OE, OE, 32); + RELEASE(OE); +} + +static void +compute_user_password_V5 (pdf_sec *p_sec, const char *uplain) +{ + unsigned char vsalt[8], ksalt[8], hash[32]; + unsigned char *UE, iv[AES_BLOCKSIZE]; + size_t UE_len; + int i; + + for (i = 0; i < 8 ; i++) { + vsalt[i] = rand() % 256; + ksalt[i] = rand() % 256; + } + + compute_hash_V5(hash, uplain, vsalt, NULL, p_sec->R); + memcpy(p_sec->U, hash, 32); + memcpy(p_sec->U + 32, vsalt, 8); + memcpy(p_sec->U + 40, ksalt, 8); + + compute_hash_V5(hash, uplain, ksalt, NULL, p_sec->R); + memset(iv, 0, AES_BLOCKSIZE); + AES_cbc_encrypt(hash, 32, iv, 0, p_sec->key, p_sec->key_size, &UE, &UE_len); + memcpy(p_sec->UE, UE, 32); + RELEASE(UE); +} + +static void +check_version (pdf_sec *p_sec, int version) +{ + if (p_sec->V > 2 && version < 14) { + WARN("Current encryption setting requires PDF version >= 1.4."); + p_sec->V = 1; + p_sec->key_size = 5; + } else if (p_sec->V == 4 && version < 15) { + WARN("Current encryption setting requires PDF version >= 1.5."); + p_sec->V = 2; + } else if (p_sec->V ==5 && version < 17) { + WARN("Current encryption setting requires PDF version >= 1.7" \ + " (plus Adobe Extension Level 3)."); + p_sec->V = 4; + p_sec->key_size = 16; + } + if (p_sec->V == 5 && version < 20) { + p_sec->setting.need_adobe_extension = 1; + } +} + +/* Dummy routine for stringprep - NOT IMPLEMENTED YET + * + * Preprocessing of a user-provided password consists first of + * normalizing its representation by applying the "SASLPrep" profile (RFC 4013) + * of the "stringprep" algorithm (RFC 3454) to the supplied password using the + * Normalize and BiDi options. + */ +typedef int Stringprep_profile_flags; +#define STRINGPREP_OK 0 +#define STRINGPREP_ERROR -1 +static int +stringprep_profile(const char *input, char **output, const char *profile, + Stringprep_profile_flags flags) +{ + const char *p, *endptr; + + p = input; endptr = p + strlen(p); + while (p < endptr) { + int32_t ucv = UC_UTF8_decode_char((const unsigned char **)&p, + (const unsigned char *)endptr); + if (!UC_is_valid(ucv)) + return STRINGPREP_ERROR; + } + + *output = NEW(strlen(input) + 1, char); + strcpy(*output, input); + + (void) profile; + (void) flags; + + return STRINGPREP_OK; +} + +static int +preproc_password (const char *passwd, char *outbuf, int V) +{ + char *saslpwd = NULL; + int error = 0; + + memset(outbuf, 0, 128); + switch (V) { + case 1: case 2: case 3: case 4: + { + int i; + /* Need to be converted to PDFDocEncoding - UNIMPLEMENTED */ + for (i = 0; i < strlen(passwd); i++) { + if (passwd[i] < 0x20 || passwd[i] > 0x7e) + WARN("Non-ASCII-printable character found in password."); + } + memcpy(outbuf, passwd, MIN(127, strlen(passwd))); + } + break; + case 5: + /* This is a dummy routine - not actually stringprep password... */ + if (stringprep_profile(passwd, &saslpwd, + "SASLprep", 0) != STRINGPREP_OK) + return -1; + else if (saslpwd) { + memcpy(outbuf, saslpwd, MIN(127, strlen(saslpwd))); + RELEASE(saslpwd); + } + break; + default: + error = -1; + break; + } + + return error; +} + +static void +pdf_enc_set_password (pdf_sec *p_sec, unsigned int bits, unsigned int perm, + const char *oplain, const char *uplain) +{ + char opasswd[128], upasswd[128]; + int version; + char empty_passwd[1] = "\0"; + + version = pdf_get_version(); + + p_sec->key_size = (int) (bits / 8); + if (p_sec->key_size == 5) { /* 40bit */ + p_sec->V = 1; + } else if (p_sec->key_size < 16) { + p_sec->V = 2; + } else if (p_sec->key_size == 16) { + p_sec->V = p_sec->setting.use_aes ? 4 : 2; + } else if (p_sec->key_size == 32) { + p_sec->V = 5; + } else { + WARN("Key length %d unsupported.", bits); + p_sec->key_size = 5; + p_sec->V = 2; + } + check_version(p_sec, version); + + p_sec->P = (int32_t) (perm | 0xC0U); + /* Bit position 10 shall be always set to 1 for PDF >= 2.0. */ + if (version >= 20) + p_sec->P |= (1 << 9); + switch (p_sec->V) { + case 1: + p_sec->R = (p_sec->P < 0x100L) ? 2 : 3; + break; + case 2: case 3: + p_sec->R = 3; + break; + case 4: + p_sec->R = 4; + break; + case 5: +#if USE_ADOBE_EXTENSION + p_sec->R = 6; +#else + WARN("Encryption V 5 unsupported."); + p_sec->R = 4; p_sec->V = 4; +#endif + break; + default: + p_sec->R = 3; + break; + } + + memset(opasswd, 0, 128); + memset(upasswd, 0, 128); + /* Password must be preprocessed. */ + if (oplain) { + if (preproc_password(oplain, opasswd, p_sec->V) < 0) + WARN("Invaid UTF-8 string for password."); + } else { + preproc_password(empty_passwd, opasswd, p_sec->V); + } + if (uplain) { + if (preproc_password(uplain, upasswd, p_sec->V) < 0) + WARN("Invalid UTF-8 string for passowrd."); + } else { + preproc_password(empty_passwd, upasswd, p_sec->V); + } + + if (p_sec->R >= 3) + p_sec->P |= 0xFFFFF000U; + + if (p_sec->V < 5) { + compute_owner_password(p_sec, opasswd, upasswd); + compute_user_password (p_sec, upasswd); + } else if (p_sec->V == 5) { + int i; + + for (i = 0; i < 32; i++) + p_sec->key[i] = rand() % 256; + p_sec->key_size = 32; + /* Order is important here */ + compute_user_password_V5 (p_sec, upasswd); + compute_owner_password_V5(p_sec, opasswd); /* uses p_sec->U */ + } +} + +static void +calculate_key (pdf_sec *p_sec, unsigned char *key) +{ + int len = p_sec->key_size + 5; + unsigned char tmp[25]; + MD5_CONTEXT md5; + + memcpy(tmp, p_sec->key, p_sec->key_size); + tmp[p_sec->key_size ] = (unsigned char) p_sec->label.objnum & 0xFF; + tmp[p_sec->key_size+1] = (unsigned char)(p_sec->label.objnum >> 8) & 0xFF; + tmp[p_sec->key_size+2] = (unsigned char)(p_sec->label.objnum >> 16) & 0xFF; + tmp[p_sec->key_size+3] = (unsigned char)(p_sec->label.gennum) & 0xFF; + tmp[p_sec->key_size+4] = (unsigned char)(p_sec->label.gennum >> 8) & 0xFF; + if (p_sec->V >= 4) { + tmp[p_sec->key_size + 5] = 0x73; + tmp[p_sec->key_size + 6] = 0x41; + tmp[p_sec->key_size + 7] = 0x6c; + tmp[p_sec->key_size + 8] = 0x54; + len += 4; + } + MD5_init (&md5); + MD5_write(&md5, tmp, len); + MD5_final(key, &md5); +} + +void +pdf_encrypt_data (pdf_sec *p_sec, + const unsigned char *plain, size_t plain_len, + unsigned char **cipher, size_t *cipher_len) +{ + unsigned char key[32]; + + ASSERT(p_sec); + + switch (p_sec->V) { + case 1: case 2: + calculate_key(p_sec, key); + { + ARC4_CONTEXT arc4; + + *cipher_len = plain_len; + *cipher = NEW(*cipher_len, unsigned char); + ARC4_set_key(&arc4, MIN(16, p_sec->key_size + 5), key); + ARC4(&arc4, plain_len, plain, *cipher); + } + break; + case 4: + calculate_key(p_sec, key); + AES_cbc_encrypt(key, MIN(16, p_sec->key_size + 5), NULL, 1, + plain, plain_len, cipher, cipher_len); + break; + case 5: + AES_cbc_encrypt(p_sec->key, p_sec->key_size, NULL, 1, + plain, plain_len, cipher, cipher_len); + break; + default: + ERROR("pdfencrypt: Unexpected V value: %d", p_sec->V); + break; + } +} + +pdf_obj * +pdf_enc_get_encrypt_dict (pdf_sec *p_sec) +{ + pdf_obj *doc_encrypt; + + ASSERT(p_sec); + + doc_encrypt = pdf_new_dict(); + + pdf_add_dict(doc_encrypt, pdf_new_name("Filter"), pdf_new_name("Standard")); + pdf_add_dict(doc_encrypt, pdf_new_name("V"), pdf_new_number(p_sec->V)); +#if 0 + /* PDF reference describes it as: + * + * (Optional; PDF 1.4; only if V is 2 or 3) + * + * but Acrobat *requires* this even for V 5! + */ + if (p_sec->V > 1 && p_sec->V < 4) +#endif + pdf_add_dict(doc_encrypt, + pdf_new_name("Length"), pdf_new_number(p_sec->key_size * 8)); + if (p_sec->V >= 4) { + pdf_obj *CF, *StdCF; + CF = pdf_new_dict(); + StdCF = pdf_new_dict(); + pdf_add_dict(StdCF, pdf_new_name("CFM"), + pdf_new_name( (p_sec->V == 4) ? "AESV2" : "AESV3" )); + pdf_add_dict(StdCF, pdf_new_name("AuthEvent"), pdf_new_name("DocOpen")); + pdf_add_dict(StdCF, pdf_new_name("Length"), pdf_new_number(p_sec->key_size)); + pdf_add_dict(CF, pdf_new_name("StdCF"), StdCF); + pdf_add_dict(doc_encrypt, pdf_new_name("CF"), CF); + pdf_add_dict(doc_encrypt, pdf_new_name("StmF"), pdf_new_name("StdCF")); + pdf_add_dict(doc_encrypt, pdf_new_name("StrF"), pdf_new_name("StdCF")); +#if 0 + /* NOT SUPPORTED YET */ + if (!p_sec->setting.encrypt_metadata) + pdf_add_dict(doc_encrypt, + pdf_new_name("EncryptMetadata"), pdf_new_boolean(false)); +#endif + } + pdf_add_dict(doc_encrypt, pdf_new_name("R"), pdf_new_number(p_sec->R)); + if (p_sec->V < 5) { + pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p_sec->O, 32)); + pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p_sec->U, 32)); + } else if (p_sec->V == 5) { + pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p_sec->O, 48)); + pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p_sec->U, 48)); + } + pdf_add_dict(doc_encrypt, pdf_new_name("P"), pdf_new_number(p_sec->P)); + + if (p_sec->V == 5) { + unsigned char perms[16], *cipher = NULL; + size_t cipher_len = 0; + + pdf_add_dict(doc_encrypt, pdf_new_name("OE"), pdf_new_string(p_sec->OE, 32)); + pdf_add_dict(doc_encrypt, pdf_new_name("UE"), pdf_new_string(p_sec->UE, 32)); + perms[0] = p_sec->P & 0xff; + perms[1] = (p_sec->P >> 8) & 0xff; + perms[2] = (p_sec->P >> 16) & 0xff; + perms[3] = (p_sec->P >> 24) & 0xff; + perms[4] = 0xff; + perms[5] = 0xff; + perms[6] = 0xff; + perms[7] = 0xff; + perms[8] = p_sec->setting.encrypt_metadata ? 'T' : 'F'; + perms[9] = 'a'; + perms[10] = 'd'; + perms[11] = 'b'; + perms[12] = 0; + perms[13] = 0; + perms[14] = 0; + perms[15] = 0; + AES_ecb_encrypt(p_sec->key, p_sec->key_size, perms, 16, &cipher, &cipher_len); + pdf_add_dict(doc_encrypt, + pdf_new_name("Perms"), pdf_new_string(cipher, cipher_len)); + RELEASE(cipher); + } + + return doc_encrypt; +} + +pdf_obj * +pdf_enc_get_extension_dict (pdf_sec *p_sec) +{ + pdf_obj *ext = NULL, *adbe; + + ASSERT(p_sec); + +#ifdef USE_ADOBE_EXTENSION + if (p_sec->setting.need_adobe_extension) { + ext = pdf_new_dict(); + adbe = pdf_new_dict(); + + pdf_add_dict(adbe, pdf_new_name("BaseVersion"), pdf_new_name("1.7")); + pdf_add_dict(adbe, pdf_new_name("ExtensionLevel"), + pdf_new_number(p_sec->R == 5 ? 3 : 8)); + pdf_add_dict(ext, pdf_new_name("ADBE"), adbe); + } +#endif + + return ext; +} + +void pdf_enc_set_label (pdf_sec *p_sec, unsigned label) +{ + ASSERT(p_sec); + + p_sec->label.objnum = label; +} + +void pdf_enc_set_generation (pdf_sec *p_sec, unsigned generation) +{ + ASSERT(p_sec); + + p_sec->label.gennum = generation; +} |