/**
  * This will get the character set for the font.
  *
  * @return The character set value.
  */
 public String getCharSet() {
   String retval = null;
   COSString name = (COSString) dic.getDictionaryObject(COSName.CHAR_SET);
   if (name != null) {
     retval = name.getString();
   }
   return retval;
 }
 /**
  * A string representing the preferred font family.
  *
  * @return The font family.
  */
 public String getFontFamily() {
   String retval = null;
   COSString name = (COSString) dic.getDictionaryObject(COSName.FONT_FAMILY);
   if (name != null) {
     retval = name.getString();
   }
   return retval;
 }
Example #3
0
 /**
  * This will draw a string at the current location on the screen.
  *
  * @param text The text to draw.
  * @throws IOException If an io exception occurs.
  */
 public void drawString(String text) throws IOException {
   if (!inTextMode) {
     throw new IOException("Error: must call beginText() before drawString");
   }
   COSString string = new COSString(text);
   ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   string.writePDF(buffer);
   appendRawCommands(new String(buffer.toByteArray(), "ISO-8859-1"));
   appendRawCommands(SPACE);
   appendRawCommands(SHOW_TEXT);
 }
 private String getTrailerID(COSArray ids) {
   if (ids != null) {
     StringBuilder builder = new StringBuilder();
     for (COSBase id : ids) {
       builder.append(((COSString) id).getASCII()).append(' ');
     }
     // need to discard last whitespace
     return builder.toString().substring(0, builder.length() - 2);
   } else {
     return null;
   }
 }
  /**
   * Prepare the document for encryption.
   *
   * @param doc The document that will be encrypted.
   * @throws CryptographyException If there is an error while encrypting.
   */
  public void prepareDocumentForEncryption(PDDocument doc) throws CryptographyException {

    try {
      Security.addProvider(new BouncyCastleProvider());

      PDEncryptionDictionary dictionary = doc.getEncryptionDictionary();
      if (dictionary == null) {
        dictionary = new PDEncryptionDictionary();
      }

      dictionary.setFilter(FILTER);
      dictionary.setLength(this.keyLength);
      dictionary.setVersion(2);
      dictionary.setSubFilter(SUBFILTER);

      byte[][] recipientsField = new byte[policy.getRecipientsNumber()][];

      // create the 20 bytes seed

      byte[] seed = new byte[20];

      KeyGenerator key = KeyGenerator.getInstance("AES");
      key.init(192, new SecureRandom());
      SecretKey sk = key.generateKey();
      System.arraycopy(sk.getEncoded(), 0, seed, 0, 20); // create the 20 bytes seed

      Iterator it = policy.getRecipientsIterator();
      int i = 0;

      while (it.hasNext()) {
        PublicKeyRecipient recipient = (PublicKeyRecipient) it.next();
        X509Certificate certificate = recipient.getX509();
        int permission = recipient.getPermission().getPermissionBytesForPublicKey();

        byte[] pkcs7input = new byte[24];
        byte one = (byte) (permission);
        byte two = (byte) (permission >>> 8);
        byte three = (byte) (permission >>> 16);
        byte four = (byte) (permission >>> 24);

        System.arraycopy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input

        pkcs7input[20] = four;
        pkcs7input[21] = three;
        pkcs7input[22] = two;
        pkcs7input[23] = one;

        DERObject obj = createDERForRecipient(pkcs7input, certificate);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        DEROutputStream k = new DEROutputStream(baos);

        k.writeObject(obj);

        recipientsField[i] = baos.toByteArray();

        i++;
      }

      dictionary.setRecipients(recipientsField);

      int sha1InputLength = seed.length;

      for (int j = 0; j < dictionary.getRecipientsLength(); j++) {
        COSString string = dictionary.getRecipientStringAt(j);
        sha1InputLength += string.getBytes().length;
      }

      byte[] sha1Input = new byte[sha1InputLength];

      System.arraycopy(seed, 0, sha1Input, 0, 20);

      int sha1InputOffset = 20;

      for (int j = 0; j < dictionary.getRecipientsLength(); j++) {
        COSString string = dictionary.getRecipientStringAt(j);
        System.arraycopy(
            string.getBytes(), 0, sha1Input, sha1InputOffset, string.getBytes().length);
        sha1InputOffset += string.getBytes().length;
      }

      MessageDigest md = MessageDigest.getInstance("SHA-1");

      byte[] mdResult = md.digest(sha1Input);

      this.encryptionKey = new byte[this.keyLength / 8];
      System.arraycopy(mdResult, 0, this.encryptionKey, 0, this.keyLength / 8);

      doc.setEncryptionDictionary(dictionary);
      doc.getDocument().setEncryptionDictionary(dictionary.encryptionDictionary);

    } catch (NoSuchAlgorithmException ex) {
      throw new CryptographyException(ex);
    } catch (NoSuchProviderException ex) {
      throw new CryptographyException(ex);
    } catch (Exception e) {
      e.printStackTrace();
      throw new CryptographyException(e);
    }
  }
  /**
   * Prepares everything to decrypt the document.
   *
   * <p>If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, this method is called
   * from there. Only if decryption of single objects is needed this should be called instead.
   *
   * @param encDictionary encryption dictionary, can be retrieved via {@link
   *     PDDocument#getEncryptionDictionary()}
   * @param documentIDArray document id which is returned via {@link COSDocument#getDocumentID()}
   *     (not used by this handler)
   * @param decryptionMaterial Information used to decrypt the document.
   * @throws IOException If there is an error accessing data.
   * @throws CryptographyException If there is an error with decryption.
   */
  public void prepareForDecryption(
      PDEncryptionDictionary encDictionary,
      COSArray documentIDArray,
      DecryptionMaterial decryptionMaterial)
      throws CryptographyException, IOException {

    if (encDictionary.getLength() != 0) {
      this.keyLength = encDictionary.getLength();
    }

    if (!(decryptionMaterial instanceof PublicKeyDecryptionMaterial)) {
      throw new CryptographyException(
          "Provided decryption material is not compatible with the document");
    }

    PublicKeyDecryptionMaterial material = (PublicKeyDecryptionMaterial) decryptionMaterial;

    try {
      boolean foundRecipient = false;

      // the decrypted content of the enveloped data that match
      // the certificate in the decryption material provided
      byte[] envelopedData = null;

      // the bytes of each recipient in the recipients array
      byte[][] recipientFieldsBytes = new byte[encDictionary.getRecipientsLength()][];

      int recipientFieldsLength = 0;

      for (int i = 0; i < encDictionary.getRecipientsLength(); i++) {
        COSString recipientFieldString = encDictionary.getRecipientStringAt(i);
        byte[] recipientBytes = recipientFieldString.getBytes();
        CMSEnvelopedData data = new CMSEnvelopedData(recipientBytes);
        Iterator recipCertificatesIt = data.getRecipientInfos().getRecipients().iterator();
        while (recipCertificatesIt.hasNext()) {
          RecipientInformation ri = (RecipientInformation) recipCertificatesIt.next();
          // Impl: if a matching certificate was previously found it is an error,
          // here we just don't care about it
          if (ri.getRID().match(material.getCertificate()) && !foundRecipient) {
            foundRecipient = true;
            envelopedData = ri.getContent(material.getPrivateKey(), "BC");
          }
        }
        recipientFieldsBytes[i] = recipientBytes;
        recipientFieldsLength += recipientBytes.length;
      }
      if (!foundRecipient || envelopedData == null) {
        throw new CryptographyException("The certificate matches no recipient entry");
      }
      if (envelopedData.length != 24) {
        throw new CryptographyException("The enveloped data does not contain 24 bytes");
      }
      // now envelopedData contains:
      // - the 20 bytes seed
      // - the 4 bytes of permission for the current user

      byte[] accessBytes = new byte[4];
      System.arraycopy(envelopedData, 20, accessBytes, 0, 4);

      currentAccessPermission = new AccessPermission(accessBytes);
      currentAccessPermission.setReadOnly();

      // what we will put in the SHA1 = the seed + each byte contained in the recipients array
      byte[] sha1Input = new byte[recipientFieldsLength + 20];

      // put the seed in the sha1 input
      System.arraycopy(envelopedData, 0, sha1Input, 0, 20);

      // put each bytes of the recipients array in the sha1 input
      int sha1InputOffset = 20;
      for (int i = 0; i < recipientFieldsBytes.length; i++) {
        System.arraycopy(
            recipientFieldsBytes[i], 0, sha1Input, sha1InputOffset, recipientFieldsBytes[i].length);
        sha1InputOffset += recipientFieldsBytes[i].length;
      }

      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] mdResult = md.digest(sha1Input);

      // we have the encryption key ...
      encryptionKey = new byte[this.keyLength / 8];
      System.arraycopy(mdResult, 0, encryptionKey, 0, this.keyLength / 8);
    } catch (CMSException e) {
      throw new CryptographyException(e);
    } catch (KeyStoreException e) {
      throw new CryptographyException(e);
    } catch (NoSuchProviderException e) {
      throw new CryptographyException(e);
    } catch (NoSuchAlgorithmException e) {
      throw new CryptographyException(e);
    }
  }