/** * Sign the document using an external container, usually a PKCS7. The signature is fully composed * externally, iText will just put the container inside the document. * @param sap the PdfSignatureAppearance * @param externalSignatureContainer the interface providing the actual signing * @param estimatedSize the reserved size for the signature * @throws GeneralSecurityException * @throws IOException * @throws DocumentException */ public static void SignExternalContainer(PdfSignatureAppearance sap, IExternalSignatureContainer externalSignatureContainer, int estimatedSize) { PdfSignature dic = new PdfSignature(null, null); dic.Reason = sap.Reason; dic.Location = sap.Location; dic.SignatureCreator = sap.SignatureCreator; dic.Contact = sap.Contact; dic.Date = new PdfDate(sap.SignDate); // time-stamp will over-rule this externalSignatureContainer.ModifySigningDictionary(dic); sap.CryptoDictionary = dic; Dictionary <PdfName, int> exc = new Dictionary <PdfName, int>(); exc[PdfName.CONTENTS] = estimatedSize * 2 + 2; sap.PreClose(exc); Stream data = sap.GetRangeStream(); byte[] encodedSig = externalSignatureContainer.Sign(data); if (estimatedSize < encodedSig.Length) { throw new IOException("Not enough space"); } byte[] paddedSig = new byte[estimatedSize]; System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2); }
/// <summary>Signs a PDF where space was already reserved.</summary> /// <param name="document">the original PDF</param> /// <param name="fieldName">the field to sign. It must be the last field</param> /// <param name="outs">the output PDF</param> /// <param name="externalSignatureContainer"> /// the signature container doing the actual signing. Only the /// method ExternalSignatureContainer.sign is used /// </param> /// <exception cref="System.IO.IOException"/> /// <exception cref="Org.BouncyCastle.Security.GeneralSecurityException"/> public static void SignDeferred(PdfDocument document, String fieldName, Stream outs, IExternalSignatureContainer externalSignatureContainer) { SignatureUtil signatureUtil = new SignatureUtil(document); PdfDictionary v = signatureUtil.GetSignatureDictionary(fieldName); if (v == null) { throw new PdfException(PdfException.ThereIsNoFieldInTheDocumentWithSuchName1).SetMessageParams(fieldName); } if (!signatureUtil.SignatureCoversWholeDocument(fieldName)) { new PdfException(PdfException.SignatureWithName1IsNotTheLastItDoesntCoverWholeDocument).SetMessageParams(fieldName ); } PdfArray b = v.GetAsArray(PdfName.ByteRange); long[] gaps = SignatureUtil.AsLongArray(b); // TODO: refactor if (b.Size() != 4 || gaps[0] != 0) { throw new ArgumentException("Single exclusion space supported"); } IRandomAccessSource readerSource = document.GetReader().GetSafeFile().CreateSourceView(); Stream rg = new RASInputStream(new RandomAccessSourceFactory().CreateRanged(readerSource, gaps)); byte[] signedContent = externalSignatureContainer.Sign(rg); int spaceAvailable = (int)(gaps[2] - gaps[1]) - 2; if ((spaceAvailable & 1) != 0) { throw new ArgumentException("Gap is not a multiple of 2"); } spaceAvailable /= 2; if (spaceAvailable < signedContent.Length) { throw new PdfException(PdfException.AvailableSpaceIsNotEnoughForSignature); } StreamUtil.CopyBytes(readerSource, 0, gaps[1] + 1, outs); ByteBuffer bb = new ByteBuffer(spaceAvailable * 2); foreach (byte bi in signedContent) { bb.AppendHex(bi); } int remain = (spaceAvailable - signedContent.Length) * 2; for (int k = 0; k < remain; ++k) { bb.Append((byte)48); } byte[] bbArr = bb.ToByteArray(); outs.Write(bbArr); StreamUtil.CopyBytes(readerSource, gaps[2] - 1, gaps[3] + 1, outs); }
/** * Signs a PDF where space was already reserved. * @param reader the original PDF * @param fieldName the field to sign. It must be the last field * @param outs the output PDF * @param externalSignatureContainer the signature container doing the actual signing. Only the * method ExternalSignatureContainer.sign is used * @throws DocumentException * @throws IOException * @throws GeneralSecurityException */ public static void SignDeferred(PdfReader reader, String fieldName, Stream outs, IExternalSignatureContainer externalSignatureContainer) { AcroFields af = reader.AcroFields; PdfDictionary v = af.GetSignatureDictionary(fieldName); if (v == null) { throw new DocumentException("No field"); } if (!af.SignatureCoversWholeDocument(fieldName)) { throw new DocumentException("Not the last signature"); } PdfArray b = v.GetAsArray(PdfName.BYTERANGE); long[] gaps = b.AsLongArray(); if (b.Size != 4 || gaps[0] != 0) { throw new DocumentException("Single exclusion space supported"); } IRandomAccessSource readerSource = reader.SafeFile.CreateSourceView(); Stream rg = new RASInputStream(new RandomAccessSourceFactory().CreateRanged(readerSource, gaps)); byte[] signedContent = externalSignatureContainer.Sign(rg); int spaceAvailable = (int)(gaps[2] - gaps[1]) - 2; if ((spaceAvailable & 1) != 0) { throw new DocumentException("Gap is not a multiple of 2"); } spaceAvailable /= 2; if (spaceAvailable < signedContent.Length) { throw new DocumentException("Not enough space"); } StreamUtil.CopyBytes(readerSource, 0, gaps[1] + 1, outs); ByteBuffer bb = new ByteBuffer(spaceAvailable * 2); foreach (byte bi in signedContent) { bb.AppendHex(bi); } int remain = (spaceAvailable - signedContent.Length) * 2; for (int k = 0; k < remain; ++k) { bb.Append((byte)48); } bb.WriteTo(outs); StreamUtil.CopyBytes(readerSource, gaps[2] - 1, gaps[3] + 1, outs); }
/// <summary>Sign the document using an external container, usually a PKCS7.</summary> /// <remarks> /// Sign the document using an external container, usually a PKCS7. The signature is fully composed /// externally, iText will just put the container inside the document. /// <br /><br /> /// NOTE: This method closes the underlying pdf document. This means, that current instance /// of PdfSigner cannot be used after this method call. /// </remarks> /// <param name="externalSignatureContainer">the interface providing the actual signing</param> /// <param name="estimatedSize">the reserved size for the signature</param> /// <exception cref="Org.BouncyCastle.Security.GeneralSecurityException"/> /// <exception cref="System.IO.IOException"/> public virtual void SignExternalContainer(IExternalSignatureContainer externalSignatureContainer, int estimatedSize ) { if (closed) { throw new PdfException(PdfException.ThisInstanceOfPdfSignerAlreadyClosed); } PdfSignature dic = new PdfSignature(); PdfSignatureAppearance appearance = GetSignatureAppearance(); dic.SetReason(appearance.GetReason()); dic.SetLocation(appearance.GetLocation()); dic.SetSignatureCreator(appearance.GetSignatureCreator()); dic.SetContact(appearance.GetContact()); dic.SetDate(new PdfDate(GetSignDate())); // time-stamp will over-rule this externalSignatureContainer.ModifySigningDictionary(dic.GetPdfObject()); cryptoDictionary = dic; IDictionary <PdfName, int?> exc = new Dictionary <PdfName, int?>(); exc[PdfName.Contents] = estimatedSize * 2 + 2; PreClose(exc); Stream data = GetRangeStream(); byte[] encodedSig = externalSignatureContainer.Sign(data); if (estimatedSize < encodedSig.Length) { throw new System.IO.IOException("Not enough space"); } byte[] paddedSig = new byte[estimatedSize]; System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true)); Close(dic2); closed = true; }
/** * Signs a PDF where space was already reserved. * @param reader the original PDF * @param fieldName the field to sign. It must be the last field * @param outs the output PDF * @param externalSignatureContainer the signature container doing the actual signing. Only the * method ExternalSignatureContainer.sign is used * @throws DocumentException * @throws IOException * @throws GeneralSecurityException */ public static void SignDeferred(PdfReader reader, String fieldName, Stream outs, IExternalSignatureContainer externalSignatureContainer) { AcroFields af = reader.AcroFields; PdfDictionary v = af.GetSignatureDictionary(fieldName); if (v == null) throw new DocumentException("No field"); if (!af.SignatureCoversWholeDocument(fieldName)) throw new DocumentException("Not the last signature"); PdfArray b = v.GetAsArray(PdfName.BYTERANGE); long[] gaps = b.AsLongArray(); if (b.Size != 4 || gaps[0] != 0) throw new DocumentException("Single exclusion space supported"); IRandomAccessSource readerSource = reader.SafeFile.CreateSourceView(); Stream rg = new RASInputStream(new RandomAccessSourceFactory().CreateRanged(readerSource, gaps)); byte[] signedContent = externalSignatureContainer.Sign(rg); int spaceAvailable = (int)(gaps[2] - gaps[1]) - 2; if ((spaceAvailable & 1) != 0) throw new DocumentException("Gap is not a multiple of 2"); spaceAvailable /= 2; if (spaceAvailable < signedContent.Length) throw new DocumentException("Not enough space"); StreamUtil.CopyBytes(readerSource, 0, gaps[1] + 1, outs); ByteBuffer bb = new ByteBuffer(spaceAvailable * 2); foreach (byte bi in signedContent) { bb.AppendHex(bi); } int remain = (spaceAvailable - signedContent.Length) * 2; for (int k = 0; k < remain; ++k) { bb.Append((byte)48); } bb.WriteTo(outs); StreamUtil.CopyBytes(readerSource, gaps[2] - 1, gaps[3] + 1, outs); }
/** * Sign the document using an external container, usually a PKCS7. The signature is fully composed * externally, iText will just put the container inside the document. * @param sap the PdfSignatureAppearance * @param externalSignatureContainer the interface providing the actual signing * @param estimatedSize the reserved size for the signature * @throws GeneralSecurityException * @throws IOException * @throws DocumentException */ public static void SignExternalContainer(PdfSignatureAppearance sap, IExternalSignatureContainer externalSignatureContainer, int estimatedSize) { PdfSignature dic = new PdfSignature(null, null); dic.Reason = sap.Reason; dic.Location = sap.Location; dic.SignatureCreator = sap.SignatureCreator; dic.Contact = sap.Contact; dic.Date = new PdfDate(sap.SignDate); // time-stamp will over-rule this externalSignatureContainer.ModifySigningDictionary(dic); sap.CryptoDictionary = dic; Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>(); exc[PdfName.CONTENTS] = estimatedSize * 2 + 2; sap.PreClose(exc); Stream data = sap.GetRangeStream(); byte[] encodedSig = externalSignatureContainer.Sign(data); if (estimatedSize < encodedSig.Length) throw new IOException("Not enough space"); byte[] paddedSig = new byte[estimatedSize]; System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2); }