Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Digital signature #243

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions PdfSharpCore.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29911.84
# Visual Studio Version 17
VisualStudioVersion = 17.2.32519.379
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharpCore", "PdfSharpCore\PdfSharpCore.csproj", "{4005DEBC-75F8-48DA-BBCC-353E17872B3E}"
EndProject
Expand All @@ -18,6 +18,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharpCore.Test", "PdfSharpCore.Test\PdfSharpCore.Test.csproj", "{A862C0CE-C095-459C-A32B-8FCDD15A93BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignatureTestConsole", "SignatureTestConsole\SignatureTestConsole.csproj", "{272E99C1-3210-497B-8CCE-D561E353FC13}"
ProjectSection(ProjectDependencies) = postProject
{4005DEBC-75F8-48DA-BBCC-353E17872B3E} = {4005DEBC-75F8-48DA-BBCC-353E17872B3E}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -44,6 +49,10 @@ Global
{A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Release|Any CPU.Build.0 = Release|Any CPU
{272E99C1-3210-497B-8CCE-D561E353FC13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{272E99C1-3210-497B-8CCE-D561E353FC13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{272E99C1-3210-497B-8CCE-D561E353FC13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{272E99C1-3210-497B-8CCE-D561E353FC13}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
26 changes: 25 additions & 1 deletion PdfSharpCore/Pdf.AcroForms/PdfAcroField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ public sealed class PdfAcroFieldCollection : PdfArray
: base(array)
{ }

PdfAcroFieldCollection(PdfDocument document)
: base(document)
{ }

/// <summary>
/// Gets the names of all fields in the collection.
/// </summary>
Expand Down Expand Up @@ -553,7 +557,27 @@ public class Keys : KeysBase
[KeyInfo(KeyType.Integer | KeyType.Optional)]
public const string Q = "/Q";

// ReSharper restore InconsistentNaming
/// <summary>
/// (Optional) The type of PDF object that this dictionary describes; if present,
/// must be Sig for a signature dictionary.
/// </summary>
[KeyInfo(KeyType.Name | KeyType.Optional)]
public const string Type = "/Type";

/// <summary>
///
/// </summary>
[KeyInfo(KeyType.Name | KeyType.Required)]
public const string Subtype = "/Subtype";

/// <summary>
///
/// </summary>
[KeyInfo(KeyType.Rectangle | KeyType.Required)]
public const string Rect = "/Rect";

[KeyInfo(KeyType.Rectangle | KeyType.Required)]
public const string P = "/P";
}
}
}
147 changes: 137 additions & 10 deletions PdfSharpCore/Pdf.AcroForms/PdfSignatureField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,157 @@
// DEALINGS IN THE SOFTWARE.
#endregion

using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf.Annotations;
using PdfSharpCore.Pdf.Signatures;
using System;

namespace PdfSharpCore.Pdf.AcroForms
{
/// <summary>
/// Represents the signature field.
/// </summary>
public sealed class PdfSignatureField : PdfAcroField
{
private bool visible;

public string Reason
{
get
{
return Elements.GetDictionary(Keys.V).Elements.GetString(Keys.Reason);
}
set
{
Elements.GetDictionary(Keys.V).Elements[Keys.Reason] = new PdfString(value);
}
}

public string Location
{
get
{
return Elements.GetDictionary(Keys.V).Elements.GetString(Keys.Location);
}
set
{
Elements.GetDictionary(Keys.V).Elements[Keys.Location] = new PdfString(value);
}
}

public PdfItem Contents
{
get
{
return Elements.GetDictionary(Keys.V).Elements[Keys.Contents];
}
set
{
Elements.GetDictionary(Keys.V).Elements.Add(Keys.Contents, value);
}
}


public PdfItem ByteRange
{
get
{
return Elements.GetDictionary(Keys.V).Elements[Keys.ByteRange];
}
set
{
Elements.GetDictionary(Keys.V).Elements.Add(Keys.ByteRange, value);
}
}


public PdfRectangle Rectangle
{
get
{
return (PdfRectangle)Elements[Keys.Rect];
}
set
{
Elements.Add(Keys.Rect, value);
this.visible = !(value.X1 + value.X2 + value.Y1 + value.Y2 == 0);

}
}


public ISignatureAppearanceHandler AppearanceHandler { get; internal set; }

/// <summary>
/// Initializes a new instance of PdfSignatureField.
/// </summary>
internal PdfSignatureField(PdfDocument document)
: base(document)
{ }
internal PdfSignatureField(PdfDocument document) : base(document)
{


Elements.Add(Keys.FT, new PdfName("/Sig"));
Elements.Add(Keys.T, new PdfString("Signature1"));
Elements.Add(Keys.Ff, new PdfInteger(132));
Elements.Add(Keys.DR, new PdfDictionary());
Elements.Add(Keys.Type, new PdfName("/Annot"));
Elements.Add(Keys.Subtype, new PdfName("/Widget"));
Elements.Add(Keys.P, document.Pages[0]);


PdfDictionary sign = new PdfDictionary(document);
sign.Elements.Add(Keys.Type, new PdfName("/Sig"));
sign.Elements.Add(Keys.Filter, new PdfName("/Adobe.PPKLite"));
sign.Elements.Add(Keys.SubFilter, new PdfName("/adbe.pkcs7.detached"));
sign.Elements.Add(Keys.M, new PdfDate(DateTime.Now));

document._irefTable.Add(sign);
document._irefTable.Add(this);

Elements.Add(Keys.V, sign);

}

internal PdfSignatureField(PdfDictionary dict)
: base(dict)
{ }


internal override void PrepareForSave()
{
if (!this.visible)
return;

if (this.AppearanceHandler == null)
throw new Exception("AppearanceHandler is null");



PdfRectangle rect = Elements.GetRectangle(PdfAnnotation.Keys.Rect);
XForm form = new XForm(this._document, rect.Size);
XGraphics gfx = XGraphics.FromForm(form);

this.AppearanceHandler.DrawAppearance(gfx, rect.ToXRect());

form.DrawingFinished();

// Get existing or create new appearance dictionary
PdfDictionary ap = Elements[PdfAnnotation.Keys.AP] as PdfDictionary;
if (ap == null)
{
ap = new PdfDictionary(this._document);
Elements[PdfAnnotation.Keys.AP] = ap;
}

// Set XRef to normal state
ap.Elements["/N"] = form.PdfForm.Reference;
}

/// <summary>
/// Predefined keys of this dictionary.
/// The description comes from PDF 1.4 Reference.
/// </summary>
public new class Keys : PdfAcroField.Keys
{
/// <summary>
/// (Optional) The type of PDF object that this dictionary describes; if present,
/// must be Sig for a signature dictionary.
/// </summary>
[KeyInfo(KeyType.Name | KeyType.Optional)]
public const string Type = "/Type";
{

/// <summary>
/// (Required; inheritable) The name of the signature handler to be used for
Expand Down Expand Up @@ -113,6 +234,12 @@ internal PdfSignatureField(PdfDictionary dict)
[KeyInfo(KeyType.TextString | KeyType.Optional)]
public const string Reason = "/Reason";

/// <summary>
/// (Optional)
/// </summary>
[KeyInfo(KeyType.TextString | KeyType.Optional)]
public const string ContactInfo = "/ContactInfo";

/// <summary>
/// Gets the KeysMeta for these keys.
/// </summary>
Expand Down
11 changes: 6 additions & 5 deletions PdfSharpCore/Pdf.Advanced/PdfCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,15 @@ internal PdfOutlineCollection Outlines
/// </summary>
public PdfAcroForm AcroForm
{
get
get { return (PdfAcroForm)Elements.GetValue(Keys.AcroForm); }
set
{
if (_acroForm == null)
_acroForm = (PdfAcroForm)Elements.GetValue(Keys.AcroForm);
return _acroForm;
if (Elements.ContainsKey(Keys.AcroForm))
Elements[Keys.AcroForm] = value;
else
Elements.Add(Keys.AcroForm, value);
}
}
PdfAcroForm _acroForm;

/// <summary>
/// Gets or sets the language identifier specifying the natural language for all text in the document.
Expand Down
2 changes: 1 addition & 1 deletion PdfSharpCore/Pdf.Advanced/PdfContents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ internal override void WriteObject(PdfWriter writer)
{
// Save two bytes in PDF stream...
if (Elements.Count == 1)
Elements[0].WriteObject(writer);
Elements[0].Write(writer);
else
base.WriteObject(writer);
}
Expand Down
2 changes: 1 addition & 1 deletion PdfSharpCore/Pdf.Advanced/PdfInternals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ public void WriteObject(Stream stream, PdfItem item)
// Never write an encrypted object
PdfWriter writer = new PdfWriter(stream, null);
writer.Options = PdfWriterOptions.OmitStream;
item.WriteObject(writer);
item.Write(writer);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion PdfSharpCore/Pdf.IO/PdfWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public void Write(PdfString value)
PdfStringEncoding encoding = (PdfStringEncoding)(value.Flags & PdfStringFlags.EncodingMask);
string pdf = (value.Flags & PdfStringFlags.HexLiteral) == 0 ?
PdfEncoders.ToStringLiteral(value.Value, encoding, SecurityHandler) :
PdfEncoders.ToHexStringLiteral(value.Value, encoding, SecurityHandler);
PdfEncoders.ToHexStringLiteral(value.Value, encoding, SecurityHandler, value.PaddingLeft);
WriteRaw(pdf);

_lastCat = CharCat.Delimiter;
Expand Down
11 changes: 9 additions & 2 deletions PdfSharpCore/Pdf.Internal/PdfEncoders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ public static string ToStringLiteral(byte[] bytes, bool unicode, PdfStandardSecu
/// <summary>
/// Converts a raw string into a raw hexadecimal string literal, possibly encrypted.
/// </summary>
public static string ToHexStringLiteral(string text, PdfStringEncoding encoding, PdfStandardSecurityHandler securityHandler)
public static string ToHexStringLiteral(string text, PdfStringEncoding encoding, PdfStandardSecurityHandler securityHandler, int paddingLeft)
{
if (String.IsNullOrEmpty(text))
if (String.IsNullOrEmpty(text) && paddingLeft == 0)
return "<>";

byte[] bytes;
Expand All @@ -274,6 +274,13 @@ public static string ToHexStringLiteral(string text, PdfStringEncoding encoding,
throw new NotImplementedException(encoding.ToString());
}

if (bytes.Length < paddingLeft)
{
byte[] tmp = new byte[paddingLeft];
Array.Copy(bytes, tmp, bytes.Length);
bytes = tmp;
}

byte[] agTemp = FormatStringLiteral(bytes, encoding == PdfStringEncoding.Unicode, true, true, securityHandler);
return RawEncoding.GetString(agTemp, 0, agTemp.Length);
}
Expand Down
32 changes: 32 additions & 0 deletions PdfSharpCore/Pdf.Signatures/DefaultAppearanceHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using PdfSharpCore.Drawing;
using PdfSharpCore.Drawing.Layout;

namespace PdfSharpCore.Pdf.Signatures
{
internal class DefaultAppearanceHandler : ISignatureAppearanceHandler
{
public string Location { get; set; }
public string Reason { get; set; }
public string Signer { get; set; }


public void DrawAppearance(XGraphics gfx, XRect rect)
{
var backColor = XColor.Empty;
var defaultText = string.Format("Signed by: {0}\nLocation: {1}\nReason: {2}\nDate: {3}", Signer, Location, Reason, DateTime.Now);

XFont font = new XFont("Verdana", 7, XFontStyle.Regular);

XTextFormatter txtFormat = new XTextFormatter(gfx);

var currentPosition = new XPoint(0, 0);

txtFormat.DrawString(defaultText,
font,
new XSolidBrush(XColor.FromKnownColor(XKnownColor.Black)),
new XRect(currentPosition.X, currentPosition.Y, rect.Width - currentPosition.X, rect.Height),
XStringFormats.TopLeft);
}
}
}
Loading