/* Updates the /ByteRange with the provided value */ private void UpdateByteRange(PdfPKCS7 pkcs7, PdfSignature signature) { PdfArray b = signature.GetByteRange(); RandomAccessFileOrArray rf = document.GetReader().GetSafeFile(); Stream rg = null; try { rg = new RASInputStream(new RandomAccessSourceFactory().CreateRanged(rf.CreateSourceView(), b.ToLongArray( ))); byte[] buf = new byte[8192]; int rd; while ((rd = rg.JRead(buf, 0, buf.Length)) > 0) { pkcs7.Update(buf, 0, rd); } } catch (Exception e) { throw new PdfException(e); } finally { try { if (rg != null) { rg.Dispose(); } } catch (System.IO.IOException e) { // this really shouldn't ever happen - the source view we use is based on a Safe view, which is a no-op anyway throw new PdfException(e); } } }
/// <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); }