use of com.tom_roush.pdfbox.cos.COSName in project PdfBox-Android by TomRoush.
the class PDStream method getFilters.
/**
* This will get the list of filters that are associated with this stream.
* Or null if there are none.
*
* @return A list of all encoding filters to apply to this stream.
*/
public List<COSName> getFilters() {
List<COSName> retval = null;
COSBase filters = stream.getFilters();
if (filters instanceof COSName) {
COSName name = (COSName) filters;
retval = new COSArrayList<COSName>(name, name, stream, COSName.FILTER);
} else if (filters instanceof COSArray) {
retval = (List<COSName>) ((COSArray) filters).toList();
}
return retval;
}
use of com.tom_roush.pdfbox.cos.COSName in project PdfBox-Android by TomRoush.
the class AppearanceGeneratorHelper method validateAndEnsureAcroFormResources.
/*
* Adobe Reader/Acrobat are adding resources which are at the field/widget level
* to the AcroForm level.
*/
private void validateAndEnsureAcroFormResources() {
// to match Adobe Reader/Acrobat behavior
if (field.getAcroForm().getDefaultResources() == null) {
return;
}
PDResources acroFormResources = field.getAcroForm().getDefaultResources();
for (PDAnnotationWidget widget : field.getWidgets()) {
if (widget.getNormalAppearanceStream() != null && widget.getNormalAppearanceStream().getResources() != null) {
PDResources widgetResources = widget.getNormalAppearanceStream().getResources();
for (COSName fontResourceName : widgetResources.getFontNames()) {
try {
if (acroFormResources.getFont(fontResourceName) == null) {
Log.d("PdfBox-Android", "Adding font resource " + fontResourceName + " from widget to AcroForm");
acroFormResources.put(fontResourceName, widgetResources.getFont(fontResourceName));
}
} catch (IOException e) {
Log.w("PdfBox-Android", "Unable to match field level font with AcroForm font");
}
}
}
}
}
use of com.tom_roush.pdfbox.cos.COSName in project PdfBox-Android by TomRoush.
the class PDAcroForm method resolveNeedsTranslation.
/**
* Check if there is a translation needed to place the annotations content.
*
* @param appearanceStream
* @return the need for a translation transformation.
*/
private boolean resolveNeedsTranslation(PDAppearanceStream appearanceStream) {
boolean needsTranslation = true;
PDResources resources = appearanceStream.getResources();
if (resources != null && resources.getXObjectNames().iterator().hasNext()) {
Iterator<COSName> xObjectNames = resources.getXObjectNames().iterator();
while (xObjectNames.hasNext()) {
try {
// if the BBox of the PDFormXObject does not start at 0,0
// there is no need do translate as this is done by the BBox definition.
PDXObject xObject = resources.getXObject(xObjectNames.next());
if (xObject instanceof PDFormXObject) {
PDRectangle bbox = ((PDFormXObject) xObject).getBBox();
float llX = bbox.getLowerLeftX();
float llY = bbox.getLowerLeftY();
if (Float.compare(llX, 0) != 0 && Float.compare(llY, 0) != 0) {
needsTranslation = false;
}
}
} catch (IOException e) {
// we can safely ignore the exception here
// as this might only cause a misplacement
}
}
return needsTranslation;
}
return true;
}
use of com.tom_roush.pdfbox.cos.COSName in project PdfBox-Android by TomRoush.
the class PublicKeySecurityHandler method prepareForDecryption.
/**
* Prepares everything to decrypt the document.
*
* @param encryption encryption dictionary, can be retrieved via
* {@link PDDocument#getEncryption()}
* @param documentIDArray document id which is returned via
* {@link com.tom_roush.pdfbox.cos.COSDocument#getDocumentID()} (not used by
* this handler)
* @param decryptionMaterial Information used to decrypt the document.
*
* @throws IOException If there is an error accessing data. If verbose mode
* is enabled, the exception message will provide more details why the
* match wasn't successful.
*/
@Override
public void prepareForDecryption(PDEncryption encryption, COSArray documentIDArray, DecryptionMaterial decryptionMaterial) throws IOException {
if (!(decryptionMaterial instanceof PublicKeyDecryptionMaterial)) {
throw new IOException("Provided decryption material is not compatible with the document");
}
setDecryptMetadata(encryption.isEncryptMetaData());
if (encryption.getLength() != 0) {
this.keyLength = encryption.getLength();
}
PublicKeyDecryptionMaterial material = (PublicKeyDecryptionMaterial) decryptionMaterial;
try {
boolean foundRecipient = false;
X509Certificate certificate = material.getCertificate();
X509CertificateHolder materialCert = null;
if (certificate != null) {
materialCert = new X509CertificateHolder(certificate.getEncoded());
}
// 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
COSArray array = (COSArray) encryption.getCOSObject().getItem(COSName.RECIPIENTS);
if (array == null) {
PDCryptFilterDictionary defaultCryptFilterDictionary = encryption.getDefaultCryptFilterDictionary();
array = (COSArray) defaultCryptFilterDictionary.getCOSObject().getItem(COSName.RECIPIENTS);
}
byte[][] recipientFieldsBytes = new byte[array.size()][];
// TODO encryption.getRecipientsLength() and getRecipientStringAt() should be deprecated
int recipientFieldsLength = 0;
StringBuilder extraInfo = new StringBuilder();
for (int i = 0; i < array.size(); i++) {
COSString recipientFieldString = (COSString) array.getObject(i);
byte[] recipientBytes = recipientFieldString.getBytes();
CMSEnvelopedData data = new CMSEnvelopedData(recipientBytes);
Collection<RecipientInformation> recipCertificatesIt = data.getRecipientInfos().getRecipients();
int j = 0;
for (RecipientInformation ri : recipCertificatesIt) {
// Impl: if a matching certificate was previously found it is an error,
// here we just don't care about it
RecipientId rid = ri.getRID();
if (!foundRecipient && rid.match(materialCert)) {
foundRecipient = true;
PrivateKey privateKey = (PrivateKey) material.getPrivateKey();
// might need to call setContentProvider() if we use PKI token, see
// http://bouncy-castle.1462172.n4.nabble.com/CMSException-exception-unwrapping-key-key-invalid-unknown-key-type-passed-to-RSA-td4658109.html
envelopedData = ri.getContent(new JceKeyTransEnvelopedRecipient(privateKey));
break;
}
j++;
if (certificate != null) {
extraInfo.append('\n');
extraInfo.append(j);
extraInfo.append(": ");
if (rid instanceof KeyTransRecipientId) {
appendCertInfo(extraInfo, (KeyTransRecipientId) rid, certificate, materialCert);
}
}
}
recipientFieldsBytes[i] = recipientBytes;
recipientFieldsLength += recipientBytes.length;
}
if (!foundRecipient || envelopedData == null) {
throw new IOException("The certificate matches none of " + array.size() + " recipient entries" + extraInfo.toString());
}
if (envelopedData.length != 24) {
throw new IOException("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);
AccessPermission currentAccessPermission = new AccessPermission(accessBytes);
currentAccessPermission.setReadOnly();
setCurrentAccessPermission(currentAccessPermission);
// 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 (byte[] recipientFieldsByte : recipientFieldsBytes) {
System.arraycopy(recipientFieldsByte, 0, sha1Input, sha1InputOffset, recipientFieldsByte.length);
sha1InputOffset += recipientFieldsByte.length;
}
byte[] mdResult;
if (encryption.getVersion() == 4 || encryption.getVersion() == 5) {
mdResult = MessageDigests.getSHA256().digest(sha1Input);
// detect whether AES encryption is used. This assumes that the encryption algo is
// stored in the PDCryptFilterDictionary
// However, crypt filters are used only when V is 4 or 5.
PDCryptFilterDictionary defaultCryptFilterDictionary = encryption.getDefaultCryptFilterDictionary();
if (defaultCryptFilterDictionary != null) {
COSName cryptFilterMethod = defaultCryptFilterDictionary.getCryptFilterMethod();
setAES(COSName.AESV2.equals(cryptFilterMethod) || COSName.AESV3.equals(cryptFilterMethod));
}
} else {
mdResult = MessageDigests.getSHA1().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 IOException(e);
} catch (KeyStoreException e) {
throw new IOException(e);
} catch (CertificateEncodingException e) {
throw new IOException(e);
}
}
use of com.tom_roush.pdfbox.cos.COSName in project PdfBox-Android by TomRoush.
the class PublicKeySecurityHandler method prepareDocumentForEncryption.
/**
* Prepare the document for encryption.
*
* @param doc The document that will be encrypted.
*
* @throws IOException If there is an error while encrypting.
*/
@Override
public void prepareDocumentForEncryption(PDDocument doc) throws IOException {
try {
PDEncryption dictionary = doc.getEncryption();
if (dictionary == null) {
dictionary = new PDEncryption();
}
dictionary.setFilter(FILTER);
dictionary.setLength(this.keyLength);
int version = computeVersionNumber();
dictionary.setVersion(version);
// remove CF, StmF, and StrF entries that may be left from a previous encryption
dictionary.removeV45filters();
// create the 20 bytes seed
byte[] seed = new byte[20];
KeyGenerator key;
try {
key = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
// should never happen
throw new RuntimeException(e);
}
key.init(192, new SecureRandom());
SecretKey sk = key.generateKey();
// create the 20 bytes seed
System.arraycopy(sk.getEncoded(), 0, seed, 0, 20);
byte[][] recipientsFields = computeRecipientsField(seed);
int shaInputLength = seed.length;
for (byte[] field : recipientsFields) {
shaInputLength += field.length;
}
byte[] shaInput = new byte[shaInputLength];
System.arraycopy(seed, 0, shaInput, 0, 20);
int shaInputOffset = 20;
for (byte[] recipientsField : recipientsFields) {
System.arraycopy(recipientsField, 0, shaInput, shaInputOffset, recipientsField.length);
shaInputOffset += recipientsField.length;
}
byte[] mdResult;
if (version == 4 || version == 5) {
dictionary.setSubFilter(SUBFILTER5);
mdResult = MessageDigests.getSHA256().digest(shaInput);
COSName aesVName = version == 5 ? COSName.AESV3 : COSName.AESV2;
prepareEncryptionDictAES(dictionary, aesVName, recipientsFields);
} else {
dictionary.setSubFilter(SUBFILTER4);
mdResult = MessageDigests.getSHA1().digest(shaInput);
dictionary.setRecipients(recipientsFields);
}
this.encryptionKey = new byte[this.keyLength / 8];
System.arraycopy(mdResult, 0, this.encryptionKey, 0, this.keyLength / 8);
doc.setEncryptionDictionary(dictionary);
doc.getDocument().setEncryptionDictionary(dictionary.getCOSObject());
} catch (GeneralSecurityException e) {
throw new IOException(e);
}
}
Aggregations