How does PdfEncryptionSettings API work in Itext? - c#

It may be I'm not familiar with the iText library, but I've got the code below for protecting the document and used "PdfWriter.ALLOW_PRINTING" for Encryption setting:
using (Stream output = new FileStream(_outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfEncryptor.Encrypt(_pdfReader, output, true, docKey, docKey, PdfWriter.ALLOW_PRINTING);
output.Close();
}
The output file it generated does have the password protection, but after I open it, the pdf could still be edited, I could change bookmarks, add comments, etc and save the changes.
Is there anything I may have missed, or how should we understand the permission settings here? My iText version is 5.5.10.0

The issue with the code above is the same user password and owner password are used. Making them different and opening document with user password resolved the issue

Related

Password-protected pdf file [duplicate]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I need to be able to remove the security/encryption from some PDF documents, preferably with the itextsharp library. This used to be possible (How to decrypt a pdf file by supplying password of the file as argument using c#?), but a more recent change to the library means that solution no longer works.
I know this can be done with the Aspose PDF library (example), but that appears to be an expensive option.
Edit
So all this time I thought I was in possession of the owner password for the document I was using to test this. But in fact the password I had was the user password. The reason I thought it was the owner password was because it worked as the owner password and other values did not work. I believe the reason the user password worked in place of the user password was the fact that the PdfReader.unethicalreading field was set to true (it's a global flag that happened to be set elsewhere in code).
In order to test code to encrypt a PDF file, we need a sample PDF that is encrypted. We'll create such a file using the EncryptPdf example.
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.setEncryption("Hello".getBytes(), "World".getBytes(),
PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA);
stamper.close();
}
With this code, I create an encrypted file hello_encrypted.pdf that I will use in the first example demonstrating how to decrypt a file.
Your original question sounds like "How can I decrypt a PDF document with the owner password?"
That is easy. The DecryptPdf example shows you how to do this:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src, "World".getBytes());
System.out.println(new String(reader.computeUserPassword()));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
}
We create a PdfReader instance passing the owner password as the second parameter. If we want to know the user password, we can use the computeUserPassword() method. Should we want to encrypt the file, than we can use the owner password we know and the user password we computed and use the setEncryption() method to reintroduce security.
However, as we didn't do this, all security is removed, which is exactly what you wanted. This can be checked by looking at the hello.pdf document.
One could argue that your question falls in the category of "It doesn't work" questions that can only be answered with an "it works for me" answer. One could vote to close your question because you didn't provide a code sample that can be use to reproduce the problem, whereas anyone can provide a code sample that proves you wrong.
Fortunately, I can read between the lines, so I have made another example.
Many PDFs are encrypted without a user password. They can be opened by anyone, but encryption is added to enforce certain restrictions (e.g. you can view the document, but you can not print it). In this case, there is only an owner password, as is shown in the EncryptPdfWithoutUserPassword example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.setEncryption(null, "World".getBytes(),
PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA);
stamper.close();
reader.close();
}
Now we get a PDF that is encrypted, but that can be opened without a user password: hello_encrypted2.pdf
We still need to know the owner password if we want to manipulate the PDF. If we don't pass the password, then iText will rightfully throw an exception:
Exception in thread "main" com.itextpdf.text.exceptions.BadPasswordException: Bad user password
at com.itextpdf.text.pdf.PdfReader.readPdf(PdfReader.java:681)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:181)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:230)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:207)
at sandbox.security.DecryptPdf.manipulatePdf(DecryptPdf.java:26)
at sandbox.security.DecryptPdf.main(DecryptPdf.java:22)
But what if we don't remember that owner password? What if the PDF was produced by a third party and we do not want to respect the wishes of that third party?
In that case, you can deliberately be unethical and change the value of the static unethicalreading variable. This is done in the DecryptPdf2 example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader.unethicalreading = true;
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
}
This example will not work if the document was encrypted with a user and an owner password, in that case, you will have to pass at least one password, either the "owner password" or the "user password" (the fact that you have access to the PDF using only the "user" password is a side-effect of unethical reading). If only an owner password was introduced, iText does not need that owner password to manipulate the PDF if you change the unethicalreading flag.
However: there used to be a bug in iText that also removed the owner password(s) in this case. That is not the desired behavior. In the first PdfDecrypt example, we saw that we can retrieve the user password (if a user password was present), but there is no way to retrieve the owner password. It is truly secret. With the older versions of iText you refer to, the owner password was removed from the file after manipulating it, and that owner password was lost for eternity.
I have fixed this bug and the fix is in release 5.3.5. As a result, the owner password is now preserved. You can check this by looking at hello2.pdf, which is the file we decrypted in an "unethical" way. (If there was an owner and a user password, both are preserved.)
Based on this research, I am making the assumption that your question is incorrect. You meant to ask: "How can I decrypt a PDF document without the owner password?" or "How can I decrypt a PDF with the user password?"
It doesn't make sense to unfix a bug that I once fixed. We will not restore the (wrong) behavior of the old iText versions, but that doesn't mean that you can't achieve what you want. You'll only have to fool iText into thinking that the PDF wasn't encrypted.
This is shown in the DecryptPdf3 example:
class MyReader extends PdfReader {
public MyReader(String filename) throws IOException {
super(filename);
}
public void decryptOnPurpose() {
encrypted = false;
}
}
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
MyReader.unethicalreading = true;
MyReader reader = new MyReader(src);
reader.decryptOnPurpose();
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
}
Instead of PdfReader, we are now using a custom subclass of PdfReader. I have named it MyReader and I have added an extra method that allows me to set the encrypted variable to false.
I still need to use unethicalreading and right after creating the MyReader instance, I have to fool this reader into thinking that the original file wasn't encrypted by using the decryptOnPurpose() method.
This results in the file hello3.pdf which is a file that is no longer encrypted with an owner password. This example can even be used to remove all passwords from a file that is encrypted with a user and an owner password as long as you have the user password.
I'll conclude this answer with a comment in answer to your remark about Aspose not being free of charge. You know that iText is free software, but you should also know that free isn't a synonym of for free. Please read my answer to the following question for more info: Is iText Java library free of charge or have any fees to be paid?
You can do it with the command line tool qpdf:
qpdf –-password=s3cr3t –-decrypt protected.pdf unprotected.pdf
qpdf also provides an API to be used from other programs.
Alternatively, you can also use the command line tool pdftk:
pdftk protected.pdf input_pw s3cr3t output unprotected.pdf

Hp Fortify: Path Manipulation erroe

I am getting the hp fortify warning for the following code:
FileStream fs = null;
StreamWriter writer = null;
try
{
fs = new FileStream(sFileName, FileMode.Open, FileAccess.Write);// Path Manipulation error
writer = new StreamWriter(fs);
I am not deleting the file in my code, So if user provide the path of some config its safe from my code, So I am not sure why this is giving warning?
Can anyone please suggest me any alternative?
Fortify doesn't know what the file is, where it is, or anything else. Write the code in a way that Fortify can see that the application is protected from malicious users.
Validate the path so that I can't pass a file named ../../../../cmdshell.aspx, don't rely on filesystem permissions. I'm assuming that at some later time you want to read that file, do the same kind of validation there.
I would also validate MIME type, file size, and check for weird characters.

Empty File Content Which Used by Another Process

I have a log file of my application, I do some manipulation by sided application on the log file.
At the end of the manipulation, I want to delete the file - which is not possible becuase file is used, so I just want to empty it - delete the contents.
I tried:
using (FileStream stream = File.Open(query.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
using (StreamWriter writer = new StreamWriter(stream, true))
{
writer.Write("");
reader.Close();
}
}
and:
using (FileStream stream = File.Open(query.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
stream.SetLength(0);
stream.Close();
}
and:
System.IO.File.WriteAllText(#"path", string.Empty);
Notihg works.
How to overrride file content?
Not at all. It will crash, because file is being used by another process
Well, it probably isn't another process, it probably is yours. You'll have to do this after closing the log file. But there's a more general fix for that. Go back to the code that creates the log file and add the FileShare.Delete option.
This option allows deleting files that are in use. You can now simply use File.Delete() in your code, even if the log file is still opened. This will put the file in a "delete pending" state, anybody that tries to open it will be slapped with an access denied error. The file on the disk will automatically disappear when the last handle to the file is closed.
Yet another useful option is FileOptions.DeleteOnClose. Now it is completely automatic, the file is automatically deleted without you having to do anything at all. I can't tell which one is best in your case, you probably want to avoid deleting the log file when your program crashed so FileShare.Delete is best.
You can use the below code too
System.IO.File.WriteAllText(#"Path of your file",string.Empty);

File Encryption and Decryption issue

I've been playing around with encrypting and decrypting files in VC# Express 2010.
All the tutorials and documentation I've seen require two FileStreams in order to encrypt the file - one for reading the unencrypted version, and the other for encrypting. When I actually wrote the code it kept throwing an error telling me it could not open the file because it was opened by another process at the output filestream.
I'm assuming that's because the file is opened by the input filestream. So that means I have to specify a different filename? So even after the operation is successful I'll now have the original unencrypted file in the directory and a separate encrypted version? Doesn't that defeat the point? Or am I doing something wrong here? My code is similar to this...
public string filename = "test.xml";
using (FileStream input = new FileStream(filename, FileMode.Open, FileAccess.Read))
using (FileStream output = new FileStram(filename, FileMode.Open, FileAccess.Write))
using (....all the crypto stream and transform stuff...)
{
...do the encryption....
}
You're right but it's not defeating the point. The (streaming) crypto APIs are intended to encrypt from Src to Dst. Think encrypting output while sending/receiving over a network etc. This keeps them simple, as they should be.
You complicate the issue by using the same file for Src and Dst. That is not totally impossible but like Copying a File over itself it needs some extra care.
Consider that in general, encrypting will increase the File size. So it is not safe to Encrypt a file in place. Decrypting might be, but I wouldn't risk it.
What you need is a Temp file and a rename action after completion.
In your example, you can't create a separate filestream for both input and output on the same file, but you can create a handle that will read and write. The FileAccess enum has the flags attribute, so you'd just say var handle = new FileStream(filename, FileAccess.Read | FileAccess.Write); The obvious downside to this is you are going to have data lost if your encryption doesn't complete successfully.
I recommend having a separate file for the output though, atleast that way you won't lose data if your program breaks unexpectedly. If the encryption completes successfully, then delete the original and rename the encrypted file with the original file name.
Use File.ReadAllBytes. Then those bytes post to your encryptor, must work.
There is another parameter where you can specify whether or not to allow another process to read or write to the file.
openFile is a string that represents the file name.
using (FileStream fileIn = new FileStream(openFile, FileMode.Open, FileAccess.Read, FileShare.Write))
using (FileStream fileOut = new FileStream(openFile, FileMode.Open, FileAccess.Write, FileShare.Open))
This way, you can read and write to the same file.
while (myfileStream.Position < fileLength)
{
fileIn.Read(buffer, 0, 51200);
buffer = encrypt(buffer);
fileOut.Write(buffer, 0, 51200);
}
While this is easy and you don't have to write to a temporary file or have to move/rename etc, this can be really dangerous because if the encryption breaks suddenly for some reason, you will lose data!
Also, the encrypt function is something I implemented. AesCryptoServiceProvider along with CryptoStream can be used :)

Can I fill in an encrypted PDF with iTextSharp?

I have a fillable, saveable PDF file that has an owner password (that I don't have access to). I can fill it out in Adobe reader, export the FDF file, modify the FDF file, and then import it.
Then I tried to do it with iText for .NET. I can't create a PdfStamper from my PdfReader because I didn't provide the owner password to the reader. Is there any way to do this programmatically or must I recreate the document?
Even using FdfReader requires a PdfStamper. Am I missing anything? Anything legal that is - I'm pretty sure I could hack the document, but I can't. Ironically, recreating it would probably be ok.
This line will bypass edit password checking in iTextSharp:
PdfReader.unethicalreading = true;
[I found this question several months after it was posted and I'm posting this solution now for anyone who comes across this question in a search.]
I was in the exact same situation: my customer had a PDF with fillable fields that I needed to programmatically access. Unfortunately the PDF was password protected and they didn't have the password so I found couldn't work with their file.
What I discovered was that iTextSharp version 4.0.4 (and later) enforces password restrictions, earlier versions did not.
So I downloaded version 4.0.3 and sure enough it worked. In my case I didn't even have to change my code to use this older version.
You can download 4.0.3 (and all other versions) at SourceForge.
Two important things
Set PdfReader.unethicalreading = true to prevent BadPasswordException.
Set append mode in PdfStamper's constructor, otherwise the Adobe Reader Extensions signature becomes broken and Adobe Reader will display following message: "This document contained certain rights to enable special features in Adobe Reader. The document has been changed since it was created and these rights are no longer valid. Please contact the author for the original version of this document."
So all you need to do is this:
PdfReader.unethicalreading = true;
using (var pdfReader = new PdfReader("form.pdf"))
{
using (var outputStream = new FileStream("filled.pdf", FileMode.Create, FileAccess.Write))
{
using (var stamper = new iTextSharp.text.pdf.PdfStamper(pdfReader, outputStream, '\0', true))
{
stamper.AcroFields.Xfa.FillXfaForm("data.xml");
}
}
}
See How to fill XFA form using iText?
Unless someone else chimes in, I'll assume the answer is "No"
I wound up regenerating the PDF in an unencrypted form.

Categories