1 49 50 package com.lowagie.text.pdf; 51 52 import com.lowagie.text.pdf.crypto.ARCFOUREncryption; 53 54 import java.io.IOException ; 55 import java.io.OutputStream ; 56 import java.io.ByteArrayOutputStream ; 57 import java.security.MessageDigest ; 58 import java.security.cert.Certificate ; 59 60 import com.lowagie.text.ExceptionConverter; 61 62 67 public class PdfEncryption { 68 69 public static final int STANDARD_ENCRYPTION_40 = 2; 70 71 public static final int STANDARD_ENCRYPTION_128 = 3; 72 73 public static final int AES_128 = 4; 74 75 private static final byte[] pad = { (byte) 0x28, (byte) 0xBF, (byte) 0x4E, 76 (byte) 0x5E, (byte) 0x4E, (byte) 0x75, (byte) 0x8A, (byte) 0x41, 77 (byte) 0x64, (byte) 0x00, (byte) 0x4E, (byte) 0x56, (byte) 0xFF, 78 (byte) 0xFA, (byte) 0x01, (byte) 0x08, (byte) 0x2E, (byte) 0x2E, 79 (byte) 0x00, (byte) 0xB6, (byte) 0xD0, (byte) 0x68, (byte) 0x3E, 80 (byte) 0x80, (byte) 0x2F, (byte) 0x0C, (byte) 0xA9, (byte) 0xFE, 81 (byte) 0x64, (byte) 0x53, (byte) 0x69, (byte) 0x7A }; 82 83 private static final byte[] salt = { (byte) 0x73, (byte) 0x41, (byte) 0x6c, 84 (byte) 0x54 }; 85 86 private static final byte[] metadataPad = { (byte) 255, (byte) 255, 87 (byte) 255, (byte) 255 }; 88 89 90 byte key[]; 91 92 93 int keySize; 94 95 96 byte mkey[]; 97 98 99 byte extra[] = new byte[5]; 100 101 102 MessageDigest md5; 103 104 105 byte ownerKey[] = new byte[32]; 106 107 108 byte userKey[] = new byte[32]; 109 110 111 protected PdfPublicKeySecurityHandler publicKeyHandler = null; 112 113 int permissions; 114 115 byte documentID[]; 116 117 static long seq = System.currentTimeMillis(); 118 119 private int revision; 120 121 private ARCFOUREncryption arcfour = new ARCFOUREncryption(); 122 123 124 private int keyLength; 125 126 private boolean encryptMetadata; 127 128 private int cryptoMode; 129 130 public PdfEncryption() { 131 try { 132 md5 = MessageDigest.getInstance("MD5"); 133 } catch (Exception e) { 134 throw new ExceptionConverter(e); 135 } 136 publicKeyHandler = new PdfPublicKeySecurityHandler(); 137 } 138 139 public PdfEncryption(PdfEncryption enc) { 140 this(); 141 mkey = (byte[]) enc.mkey.clone(); 142 ownerKey = (byte[]) enc.ownerKey.clone(); 143 userKey = (byte[]) enc.userKey.clone(); 144 permissions = enc.permissions; 145 if (enc.documentID != null) 146 documentID = (byte[]) enc.documentID.clone(); 147 revision = enc.revision; 148 keyLength = enc.keyLength; 149 encryptMetadata = enc.encryptMetadata; 150 publicKeyHandler = enc.publicKeyHandler; 151 } 152 153 public void setCryptoMode(int mode, int kl) { 154 cryptoMode = mode; 155 encryptMetadata = (mode & PdfWriter.DO_NOT_ENCRYPT_METADATA) == 0; 156 mode &= PdfWriter.ENCRYPTION_MASK; 157 switch (mode) { 158 case PdfWriter.STANDARD_ENCRYPTION_40: 159 encryptMetadata = true; 160 keyLength = 40; 161 revision = STANDARD_ENCRYPTION_40; 162 break; 163 case PdfWriter.STANDARD_ENCRYPTION_128: 164 if (kl > 0) 165 keyLength = kl; 166 else 167 keyLength = 128; 168 revision = STANDARD_ENCRYPTION_128; 169 break; 170 case PdfWriter.ENCRYPTION_AES_128: 171 keyLength = 128; 172 revision = AES_128; 173 break; 174 default: 175 throw new IllegalArgumentException ("No valid encryption mode"); 176 } 177 } 178 179 public int getCryptoMode() { 180 return cryptoMode; 181 } 182 183 public boolean isMetadataEncrypted() { 184 return encryptMetadata; 185 } 186 187 189 private byte[] padPassword(byte userPassword[]) { 190 byte userPad[] = new byte[32]; 191 if (userPassword == null) { 192 System.arraycopy(pad, 0, userPad, 0, 32); 193 } else { 194 System.arraycopy(userPassword, 0, userPad, 0, Math.min( 195 userPassword.length, 32)); 196 if (userPassword.length < 32) 197 System.arraycopy(pad, 0, userPad, userPassword.length, 198 32 - userPassword.length); 199 } 200 201 return userPad; 202 } 203 204 206 private byte[] computeOwnerKey(byte userPad[], byte ownerPad[]) { 207 byte ownerKey[] = new byte[32]; 208 209 byte digest[] = md5.digest(ownerPad); 210 if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { 211 byte mkey[] = new byte[keyLength / 8]; 212 for (int k = 0; k < 50; ++k) 214 System.arraycopy(md5.digest(digest), 0, digest, 0, mkey.length); 215 System.arraycopy(userPad, 0, ownerKey, 0, 32); 216 for (int i = 0; i < 20; ++i) { 217 for (int j = 0; j < mkey.length; ++j) 218 mkey[j] = (byte) (digest[j] ^ i); 219 arcfour.prepareARCFOURKey(mkey); 220 arcfour.encryptARCFOUR(ownerKey); 221 } 222 } else { 223 arcfour.prepareARCFOURKey(digest, 0, 5); 224 arcfour.encryptARCFOUR(userPad, ownerKey); 225 } 226 227 return ownerKey; 228 } 229 230 234 private void setupGlobalEncryptionKey(byte[] documentID, byte userPad[], 235 byte ownerKey[], int permissions) { 236 this.documentID = documentID; 237 this.ownerKey = ownerKey; 238 this.permissions = permissions; 239 mkey = new byte[keyLength / 8]; 241 242 md5.reset(); 244 md5.update(userPad); 245 md5.update(ownerKey); 246 247 byte ext[] = new byte[4]; 248 ext[0] = (byte) permissions; 249 ext[1] = (byte) (permissions >> 8); 250 ext[2] = (byte) (permissions >> 16); 251 ext[3] = (byte) (permissions >> 24); 252 md5.update(ext, 0, 4); 253 if (documentID != null) 254 md5.update(documentID); 255 if (!encryptMetadata) 256 md5.update(metadataPad); 257 258 byte digest[] = new byte[mkey.length]; 259 System.arraycopy(md5.digest(), 0, digest, 0, mkey.length); 260 261 if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { 263 for (int k = 0; k < 50; ++k) 264 System.arraycopy(md5.digest(digest), 0, digest, 0, mkey.length); 265 } 266 267 System.arraycopy(digest, 0, mkey, 0, mkey.length); 268 } 269 270 274 private void setupUserKey() { 276 if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { 277 md5.update(pad); 278 byte digest[] = md5.digest(documentID); 279 System.arraycopy(digest, 0, userKey, 0, 16); 280 for (int k = 16; k < 32; ++k) 281 userKey[k] = 0; 282 for (int i = 0; i < 20; ++i) { 283 for (int j = 0; j < mkey.length; ++j) 284 digest[j] = (byte) (mkey[j] ^ i); 285 arcfour.prepareARCFOURKey(digest, 0, mkey.length); 286 arcfour.encryptARCFOUR(userKey, 0, 16); 287 } 288 } else { 289 arcfour.prepareARCFOURKey(mkey); 290 arcfour.encryptARCFOUR(pad, userKey); 291 } 292 } 293 294 public void setupAllKeys(byte userPassword[], byte ownerPassword[], 297 int permissions) { 298 if (ownerPassword == null || ownerPassword.length == 0) 299 ownerPassword = md5.digest(createDocumentId()); 300 permissions |= (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) ? 0xfffff0c0 301 : 0xffffffc0; 302 permissions &= 0xfffffffc; 303 byte userPad[] = padPassword(userPassword); 306 byte ownerPad[] = padPassword(ownerPassword); 307 308 this.ownerKey = computeOwnerKey(userPad, ownerPad); 309 documentID = createDocumentId(); 310 setupByUserPad(this.documentID, userPad, this.ownerKey, permissions); 311 } 312 313 public static byte[] createDocumentId() { 314 MessageDigest md5; 315 try { 316 md5 = MessageDigest.getInstance("MD5"); 317 } catch (Exception e) { 318 throw new ExceptionConverter(e); 319 } 320 long time = System.currentTimeMillis(); 321 long mem = Runtime.getRuntime().freeMemory(); 322 String s = time + "+" + mem + "+" + (seq++); 323 return md5.digest(s.getBytes()); 324 } 325 326 328 public void setupByUserPassword(byte[] documentID, byte userPassword[], 329 byte ownerKey[], int permissions) { 330 setupByUserPad(documentID, padPassword(userPassword), ownerKey, 331 permissions); 332 } 333 334 336 private void setupByUserPad(byte[] documentID, byte userPad[], 337 byte ownerKey[], int permissions) { 338 setupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); 339 setupUserKey(); 340 } 341 342 344 public void setupByOwnerPassword(byte[] documentID, byte ownerPassword[], 345 byte userKey[], byte ownerKey[], int permissions) { 346 setupByOwnerPad(documentID, padPassword(ownerPassword), userKey, 347 ownerKey, permissions); 348 } 349 350 private void setupByOwnerPad(byte[] documentID, byte ownerPad[], 351 byte userKey[], byte ownerKey[], int permissions) { 352 byte userPad[] = computeOwnerKey(ownerKey, ownerPad); setupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); setupUserKey(); 358 } 359 360 public void setupByEncryptionKey(byte[] key, int keylength) { 361 mkey = new byte[keylength / 8]; 362 System.arraycopy(key, 0, mkey, 0, mkey.length); 363 } 364 365 public void setHashKey(int number, int generation) { 366 md5.reset(); extra[0] = (byte) number; 368 extra[1] = (byte) (number >> 8); 369 extra[2] = (byte) (number >> 16); 370 extra[3] = (byte) generation; 371 extra[4] = (byte) (generation >> 8); 372 md5.update(mkey); 373 md5.update(extra); 374 if (revision == AES_128) 375 md5.update(salt); 376 key = md5.digest(); 377 keySize = mkey.length + 5; 378 if (keySize > 16) 379 keySize = 16; 380 } 381 382 public static PdfObject createInfoId(byte id[]) { 383 ByteBuffer buf = new ByteBuffer(90); 384 buf.append('[').append('<'); 385 for (int k = 0; k < 16; ++k) 386 buf.appendHex(id[k]); 387 buf.append('>').append('<'); 388 id = createDocumentId(); 389 for (int k = 0; k < 16; ++k) 390 buf.appendHex(id[k]); 391 buf.append('>').append(']'); 392 return new PdfLiteral(buf.toByteArray()); 393 } 394 395 public PdfDictionary getEncryptionDictionary() { 396 PdfDictionary dic = new PdfDictionary(); 397 398 if (publicKeyHandler.getRecipientsSize() > 0) { 399 PdfArray recipients = null; 400 401 dic.put(PdfName.FILTER, PdfName.PUBSEC); 402 dic.put(PdfName.R, new PdfNumber(revision)); 403 404 try { 405 recipients = publicKeyHandler.getEncodedRecipients(); 406 } catch (Exception f) { 407 throw new ExceptionConverter(f); 408 } 409 410 if (revision == STANDARD_ENCRYPTION_40) { 411 dic.put(PdfName.V, new PdfNumber(1)); 412 dic.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); 413 dic.put(PdfName.RECIPIENTS, recipients); 414 } else if (revision == STANDARD_ENCRYPTION_128 && encryptMetadata) { 415 dic.put(PdfName.V, new PdfNumber(2)); 416 dic.put(PdfName.LENGTH, new PdfNumber(128)); 417 dic.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); 418 dic.put(PdfName.RECIPIENTS, recipients); 419 } else { 420 dic.put(PdfName.R, new PdfNumber(AES_128)); 421 dic.put(PdfName.V, new PdfNumber(4)); 422 dic.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S5); 423 424 PdfDictionary stdcf = new PdfDictionary(); 425 stdcf.put(PdfName.RECIPIENTS, recipients); 426 if (!encryptMetadata) 427 stdcf.put(PdfName.ENCRYPTMETADATA, PdfBoolean.PDFFALSE); 428 429 if (revision == AES_128) 430 stdcf.put(PdfName.CFM, PdfName.AESV2); 431 else 432 stdcf.put(PdfName.CFM, PdfName.V2); 433 PdfDictionary cf = new PdfDictionary(); 434 cf.put(PdfName.DEFAULTCRYPTFILER, stdcf); 435 dic.put(PdfName.CF, cf); 436 dic.put(PdfName.STRF, PdfName.DEFAULTCRYPTFILER); 437 dic.put(PdfName.STMF, PdfName.DEFAULTCRYPTFILER); 438 } 439 440 MessageDigest md = null; 441 byte[] encodedRecipient = null; 442 443 try { 444 md = MessageDigest.getInstance("SHA-1"); 445 md.update(publicKeyHandler.getSeed()); 446 for (int i = 0; i < publicKeyHandler.getRecipientsSize(); i++) { 447 encodedRecipient = publicKeyHandler.getEncodedRecipient(i); 448 md.update(encodedRecipient); 449 } 450 if (!encryptMetadata) 451 md.update(new byte[] { (byte) 255, (byte) 255, (byte) 255, 452 (byte) 255 }); 453 } catch (Exception f) { 454 throw new ExceptionConverter(f); 455 } 456 457 byte[] mdResult = md.digest(); 458 459 setupByEncryptionKey(mdResult, keyLength); 460 } else { 461 dic.put(PdfName.FILTER, PdfName.STANDARD); 462 dic.put(PdfName.O, new PdfLiteral(PdfContentByte 463 .escapeString(ownerKey))); 464 dic.put(PdfName.U, new PdfLiteral(PdfContentByte 465 .escapeString(userKey))); 466 dic.put(PdfName.P, new PdfNumber(permissions)); 467 dic.put(PdfName.R, new PdfNumber(revision)); 468 469 if (revision == STANDARD_ENCRYPTION_40) { 470 dic.put(PdfName.V, new PdfNumber(1)); 471 } else if (revision == STANDARD_ENCRYPTION_128 && encryptMetadata) { 472 dic.put(PdfName.V, new PdfNumber(2)); 473 dic.put(PdfName.LENGTH, new PdfNumber(128)); 474 475 } else { 476 if (!encryptMetadata) 477 dic.put(PdfName.ENCRYPTMETADATA, PdfBoolean.PDFFALSE); 478 dic.put(PdfName.R, new PdfNumber(AES_128)); 479 dic.put(PdfName.V, new PdfNumber(4)); 480 dic.put(PdfName.LENGTH, new PdfNumber(128)); 481 PdfDictionary stdcf = new PdfDictionary(); 482 stdcf.put(PdfName.LENGTH, new PdfNumber(16)); 483 stdcf.put(PdfName.AUTHEVENT, PdfName.DOCOPEN); 484 if (revision == AES_128) 485 stdcf.put(PdfName.CFM, PdfName.AESV2); 486 else 487 stdcf.put(PdfName.CFM, PdfName.V2); 488 PdfDictionary cf = new PdfDictionary(); 489 cf.put(PdfName.STDCF, stdcf); 490 dic.put(PdfName.CF, cf); 491 dic.put(PdfName.STRF, PdfName.STDCF); 492 dic.put(PdfName.STMF, PdfName.STDCF); 493 } 494 } 495 496 return dic; 497 } 498 499 public PdfObject getFileID() { 500 return createInfoId(documentID); 501 } 502 503 public OutputStreamEncryption getEncryptionStream(OutputStream os) { 504 return new OutputStreamEncryption(os, key, 0, keySize, revision); 505 } 506 507 public int calculateStreamSize(int n) { 508 if (revision == AES_128) 509 return (n & 0x7ffffff0) + 32; 510 else 511 return n; 512 } 513 514 public byte[] encryptByteArray(byte[] b) { 515 try { 516 ByteArrayOutputStream ba = new ByteArrayOutputStream (); 517 OutputStreamEncryption os2 = getEncryptionStream(ba); 518 os2.write(b); 519 os2.finish(); 520 return ba.toByteArray(); 521 } catch (IOException ex) { 522 throw new ExceptionConverter(ex); 523 } 524 } 525 526 public StandardDecryption getDecryptor() { 527 return new StandardDecryption(key, 0, keySize, revision); 528 } 529 530 public byte[] decryptByteArray(byte[] b) { 531 try { 532 ByteArrayOutputStream ba = new ByteArrayOutputStream (); 533 StandardDecryption dec = getDecryptor(); 534 byte[] b2 = dec.update(b, 0, b.length); 535 if (b2 != null) 536 ba.write(b2); 537 b2 = dec.finish(); 538 if (b2 != null) 539 ba.write(b2); 540 return ba.toByteArray(); 541 } catch (IOException ex) { 542 throw new ExceptionConverter(ex); 543 } 544 } 545 546 public void addRecipient(Certificate cert, int permission) { 547 documentID = createDocumentId(); 548 publicKeyHandler.addRecipient(new PdfPublicKeyRecipient(cert, 549 permission)); 550 } 551 552 public byte[] computeUserPassword(byte[] ownerPassword) { 553 byte[] userPad = computeOwnerKey(ownerKey, padPassword(ownerPassword)); 554 for (int i = 0; i < userPad.length; i++) { 555 boolean match = true; 556 for (int j = 0; j < userPad.length - i; j++) { 557 if (userPad[i + j] != pad[j]) 558 match = false; 559 break; 560 } 561 if (!match) continue; 562 byte[] userPassword = new byte[i]; 563 System.arraycopy(userPad, 0, userPassword, 0, i); 564 return userPassword; 565 } 566 return userPad; 567 } 568 } | Popular Tags |