I need to decrypt password protected PDF using itextsharp.
Code i used for this is as follows
string InputFile = #"C:\Users\Pro.pdf";
string OutputFile = #"C:\Users\DecPro.pdf";
string password = #"pswd123"; // Your Key Here
try
{
PdfReader reader = new PdfReader(InputFile, new System.Text.ASCIIEncoding().GetBytes(password));
using (MemoryStream memoryStream = new MemoryStream())
{
PdfStamper stamper = new PdfStamper(reader, memoryStream);
stamper.Close();
reader.Close();
File.WriteAllBytes(OutputFile, memoryStream.ToArray());
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
This code is perfectly working on my local machine but when i move this code to production environment we need to restart IIS. After restarting IIS it is working for first 5-10 mins then again its stop working.It does not able to decrypt PDF and saving PDF with password encryption. Can anyone help in this.
Related
I am battling with some memorystream logic.
I have a method that receives a list of Id. uses them to pull pdfs from a webserver, and merges them into one pdf.
I want to then email this pdf (working in memory only)
private Stream GetWebReport(string selected_id)
{
var IdLst = selected_id.Split(',').ToList();
MemoryStream stream = new MemoryStream();
Document document = new Document();
PdfCopy pdf = new PdfCopy(document, stream);
PdfReader reader = null;
try
{
document.Open();
foreach (var id in IdLst)
{
int i = Convert.ToInt32(id);
string invoice_url = string.Concat("http://specialurl/", id);
var urlpdf = new System.Net.WebClient().OpenRead(invoice_url);
reader = new PdfReader(urlpdf);
pdf.AddDocument(reader);
reader.Close();
}
}
catch (Exception)
{
throw;
}
finally
{
if (document != null)
{
document.Close();
}
}
return stream;
}
but when I try use the resulting stream for an email
var mem = GetWebReport(selected_id);
mem.Seek(0, SeekOrigin.Begin);
Attachment att = new Attachment(mem, "Report for you", "application/pdf");
I get told:
System.ObjectDisposedException: 'Cannot access a closed Stream.'
So I am sure that my itextsharp logic is good (When I use a filestream I get the correct results).
I am sure that my logic in passing streams is what is faulty
Use
PdfCopy pdf = new PdfCopy(document, stream);
pdf.CloseStream = false;
This will keep the stream open after closing the pdf to be used elsewhere.
This is a follow up to this SO post where I successfully implemented an AES encryption on an AML from a WinForms app to decrypting it from a Windows Service. This was ONLY IF a file like c:\test.xml was available to both programs. Otherwise, I got this dreaded Exception from the Windows Service:
Unable to load configuration data. Access to the path 'C:\worl\Project Alpha\Code\AlphaConfigurationUtility\AlphaConfigurationUtility\bin\Debug\alphaService.xml' is denied.
Obviously the hardcoding wouldn't work in Production but today, I took both the WinForm and Windows Service projects and had them write and read from the same directory. Now I am getting the same dreaded exception again.
EDIT: Could there be some permission issue for the Windows Service? It is running with an Admin account
What in this code potentially causing the file to be locked for access from the other program, the Windows Service program?
try
{
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
// var fileName = #"c:/text.xml";
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
//using (var aes = Aes.Create())
//{
// aesKey = aes.Key;
// key = Convert.ToBase64String(aes.Key);
//}
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
var aesKey = Convert.FromBase64String(sKey);
string encyptedText = EncryptDecrpt.EncryptStringToBase64String(doc.ToString(), aesKey);
File.WriteAllText(fileName, encyptedText);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
The decrypting program, the Windows service starts with and gets the exception on the File.ReadAllText:
string path = AppDomain.CurrentDomain.BaseDirectory;
eventLog1.WriteEntry(path);
string fileName = System.IO.Path.Combine(path, "alphaService.xml");
// var fileName = #"c:/text.xml";
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
Byte[] keyBytes = Convert.FromBase64String(sKey);
var encryptedText = File.ReadAllText(fileName, new ASCIIEncoding());
I can't see which statement causes the block but I had a very similar problem (in a very differnt scenario) just a few days ago. Some a calling process blocked my file. I solved it by using an explicit read-only stream. Mine was a byte stream but for you this might work:
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader rs = new StreamReader(fs))
{
string allText = rs.ReadToEnd();
}
}
I open an existing pdf. Checking for protection and ask for password if it is protected and open it with:
PdfReader pdfReader = null;
Stream outputStream = null;
PdfStamper pdfStamper = null;
try
{
pdfReader = GetPdfReaderObject();
outputStream = new FileStream(filePathDestination, FileMode.Create, FileAccess.Write, FileShare.None);
pdfStamper = new PdfStamper(pdfReader, outputStream);
PdfLayer layer = new PdfLayer("watermark", pdfStamper.Writer);
for (int pageIndex = 1; pageIndex <= pdfReader.NumberOfPages; pageIndex++) {
pdfStamper.FormFlattening = false;
iTextSharp.text.Rectangle pageRectangle = pdfReader.GetPageSizeWithRotation(pageIndex);
PdfContentByte pdfData = pdfStamper.GetOverContent(pageIndex);
pdfData.BeginLayer(layer);
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = 0.5F;
pdfData.SetGState(graphicsState);
pdfData.BeginText();
iTextSharp.text.Image watermarkImage = iTextSharp.text.Image.GetInstance(System.Drawing.Image.FromFile(watermarkImagePath), ImageFormat.Png);
float width = pageRectangle.Width;
float height = pageRectangle.Height;
watermarkImage.SetAbsolutePosition(width / 2 - watermarkImage.Width / 2, height / 2 - watermarkImage.Height / 2);
pdfData.AddImage(watermarkImage);
pdfData.EndText();
pdfData.EndLayer();
}
}
pdfStamper.Close();
outputStream.Close();
outputStream.Dispose();
pdfReader.Close();
pdfReader.Dispose();
} catch (Exception e) {
....
}
}
After my modifications I save it but the protection is destroyed.
Why the protection is destroyed?
How can I save the protection from the origin document und add it to my modified one.
Regards
You use a PdfStamper to manipulate an existing PDF.
For any source PDF: If you want the result to be encrypted, you may use the SetEncryption method appropriately.
Have a look at the EncryptionPdf.cs, especially its method EncryptPdf:
PdfReader reader = ...;
using (MemoryStream ms = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, ms))
{
stamper.SetEncryption(
USER, OWNER,
PdfWriter.ALLOW_PRINTING,
PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA
);
}
return ms.ToArray();
}
Here USER and OWNER are the user and owner passwords of your choice. You might want to use a different set of permissions.
For already encrypted source PDFs you may alternatively choose to use the PdfStamper in append mode (i.e. use a PdfStamper constructor with a bool append parameter set to true). In that case the original encryption will also be applied to the updated PDF.
Which version of iText are you using?
When a password protected PDF was opened using the owner password and manipulated by PdfStamper, all original password protection was indeed removed. This changed in iText 5.3.5. See the changelog:
Important: we now keep the original owner password when stamping a document.
In other words: with all iText versions prior to 5.3.5, the owner password is lost. Starting with 5.3.5, it should be kept.
CRM saves attachements in AnnotationBase base table.
How can I convert the text in the DocumentBody entity back to file and save it the file system?
I have got the value of the documentbody field and then try to write it in my computer but my is file corrupted.
I am using this code:
String DocumentBody = Convert.ToBase64String(
newUnicodeEncoding().GetBytes("UEsDBBQABgAIAAAAIQDQf9XuxAEAAE4HAAATAAgCW0NvbnRlbnRfVHlwZXNd Lnh/abtPgp4eu7+W68C2dvLaWtho32sTajdkFmweGeKMQYTD5MrcDFf"));
using (FileStream fs = new FileStream("c:\\1.docx", FileMode.Create, FileAccess.Write))
{
byte[] bytes = Convert.FromBase64String(DocumentBody);
fs.Write(bytes, 0, bytes.Length);
}
The string in GetBytes is the same as documentbody field in annotationBase table.
Here is the code that has always worked for me - and I can confirm this has worked for me using data retreived from CRM 4 with the CRM 4 SDK. I did a project almost exactly the same about 18 months ago where we had to archive off all the notes and e-mails from CRM.
If you are still having issues see the original source of this code
public static void ExportFile(string fileName, string content)
{
byte[] fileContent = Convert.FromBase64String(content);
using (FileStream file = new FileStream(fileName, FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(file))
{
writer.Write(fileContent,0,fileContent.Length);
writer.Close();
}
file.Close();
}
}
I truly appreciate your suggestions. I am using MVC3 and I want user to save to his own path by opening a dialog with password protected. Can you guys please help me on this.
Below is my code:
mydoc.GenerateLetter(PdfData);
string WorkingFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (MemoryStream m = new MemoryStream())
{
m.Write(mydoc.DocumentBytes, 0, mydoc.DocumentBytes.Length);
m.Seek(0, SeekOrigin.Begin);
string OutputFile = Path.Combine(WorkingFolder, PdfData.Name + ".pdf");
using (Stream output = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfReader reader = new PdfReader(m);
PdfEncryptor.Encrypt(reader, output, true, "abc123", "secret", PdfWriter.ALLOW_SCREENREADERS);
}
}
If you want to show a Save As dialog so that the user can choose the location to save the PDF file on his computer you could use the Content-Disposition HTTP header and set it to attachment. Also in an ASP.NET MVC application instead of saving the file to the server (which is what your code currently does), you should stream it to the client:
public ActionResult DownloadPdf()
{
var mydoc = ...
mydoc.GenerateLetter(PdfData);
byte[] pdf = mydoc.DocumentBytes;
var reader = new PdfReader(pdf);
using (var encrypted = new MemoryStream())
{
PdfEncryptor.Encrypt(reader, encrypted, true, "abc123", "secret", PdfWriter.ALLOW_SCREENREADERS);
return File(encrypted.ToArray(), "application/pdf", PdfData.Name + ".pdf");
}
}
Now when a user navigates to this controller action /SomeController/DownloadPdf he will be presented with a Save As dialog allowing him to download the encrypted PDF file and store it in a chosen location on his computer.