/// <summary> /// Prepare the data needed for digital signature. Unfortunately /// CAPICOM's client-side implementation both hashes **AND** signs /// passed in data instead of signing data already hashed, so the /// **entire** PDF content bytes are needed. /// </summary> /// <param name="pdfIn">PDF file contents</param> /// <returns> /// Base64 encoded PDF content bytes client will sign. /// </returns> public string PreSign(byte[] pdfIn) { byte[] pdfRawContent = null; bool isOdd = true; var timeStamp = DateTime.Now; var pdfSignature = new PdfSignature( PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED ); pdfSignature.Date = new PdfDate(timeStamp); var exclusionSizes = new Dictionary<PdfName, int>(); exclusionSizes.Add(PdfName.CONTENTS, EXCLUSION_BUFFER * 2 + 2); PdfReader reader = null; int? signedFields = null; try { var cert = new WebCertificateReader().GetSigningCertificate(); do { ++DataReadCount; reader = new PdfReader(pdfIn); _acroFieldsWorker = new AcroFieldsReader(reader.AcroFields); signedFields = signedFields ?? _acroFieldsWorker.SignedFields(); _memoryStream = new MemoryStream(); var stamper = signedFields == 0 ? PdfStamper.CreateSignature(reader, _memoryStream, '\0') : PdfStamper.CreateSignature(reader, _memoryStream, '\0', null, true) ; _signatureAppearance = stamper.SignatureAppearance; InitSignatureField(stamper); pdfSignature.Reason = Reason; _signatureAppearance.Certificate = cert; _signatureAppearance.SignDate = timeStamp; _signatureAppearance.CryptoDictionary = pdfSignature; _signatureAppearance.PreClose(exclusionSizes); using (Stream sapStream = _signatureAppearance.GetRangeStream()) { using (var ms = new MemoryStream()) { sapStream.CopyTo(ms); pdfRawContent = ms.ToArray(); } // pdfRawContent = StreamHandler.ReadAllBytes(sapStream); // fix CAPICOM's broken implemetation: signature // invalid if sapStream.Length is **ODD** if ((pdfRawContent.Length % 2) == 0) { isOdd = false; } else { Reason += "\0"; } DataSize = sapStream.Length; } // sanity check if (DataReadCount > 2) throw new InvalidOperationException("DataReadCount"); } while (isOdd); } catch { throw; } finally { HttpContext.Current.Session[InstanceLookupKey] = this; if (reader != null) { reader.Dispose(); } } return Convert.ToBase64String(pdfRawContent); }
/// <summary> /// Prepare the data needed for digital signature. Unfortunately /// CAPICOM's client-side implementation both hashes **AND** signs /// passed in data instead of signing data already hashed, so the /// **entire** PDF content bytes are needed. /// </summary> /// <param name="pdfIn">PDF file contents</param> /// <returns> /// Base64 encoded PDF content bytes client will sign. /// </returns> public string PreSign(byte[] pdfIn) { byte[] pdfRawContent = null; bool isOdd = true; var timeStamp = DateTime.Now; var pdfSignature = new PdfSignature( PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED ); pdfSignature.Date = new PdfDate(timeStamp); var exclusionSizes = new Dictionary <PdfName, int>(); exclusionSizes.Add(PdfName.CONTENTS, EXCLUSION_BUFFER * 2 + 2); PdfReader reader = null; int? signedFields = null; try { var cert = new WebCertificateReader().GetSigningCertificate(); do { ++DataReadCount; reader = new PdfReader(pdfIn); _acroFieldsWorker = new AcroFieldsReader(reader.AcroFields); signedFields = signedFields ?? _acroFieldsWorker.SignedFields(); _memoryStream = new MemoryStream(); var stamper = signedFields == 0 ? PdfStamper.CreateSignature(reader, _memoryStream, '\0') : PdfStamper.CreateSignature(reader, _memoryStream, '\0', null, true) ; _signatureAppearance = stamper.SignatureAppearance; InitSignatureField(stamper); pdfSignature.Reason = Reason; _signatureAppearance.Certificate = cert; _signatureAppearance.SignDate = timeStamp; _signatureAppearance.CryptoDictionary = pdfSignature; _signatureAppearance.PreClose(exclusionSizes); using (Stream sapStream = _signatureAppearance.GetRangeStream()) { using (var ms = new MemoryStream()) { sapStream.CopyTo(ms); pdfRawContent = ms.ToArray(); } // pdfRawContent = StreamHandler.ReadAllBytes(sapStream); // fix CAPICOM's broken implemetation: signature // invalid if sapStream.Length is **ODD** if ((pdfRawContent.Length % 2) == 0) { isOdd = false; } else { // Reason += '\0'; Reason += " "; } DataSize = sapStream.Length; } // sanity check if (DataReadCount > 200) { throw new InvalidOperationException("DataReadCount"); } } while (isOdd); } catch { throw; } finally { HttpContext.Current.Session[InstanceLookupKey] = this; if (reader != null) { reader.Dispose(); } } return(Convert.ToBase64String(pdfRawContent)); }