//SAPILogoff public static void Logoff() { int rc; rc = SAPI.Logoff(hSession); if (rc != 0) { throw new Exception("Failed in Logoff (" + rc.ToString("X") + ")"); } }
static void Main(string[] args) { const int SAPI_OK = 0; int rc; SAPICrypt SAPI = new SAPICrypt(); SESHandle sesHandle = null; // Custom Values string filePath = @"c:\temp\demo.pdf"; // PDF file to sign string username = "******"; // DSA account username string password = "******"; // DSA account password string domain = null; // DSA account domain int sigPageNum = 1; // Create signature on the first page int sigX = 145; // Signature field X location int sigY = 125; // Signature field Y location int sigWidth = 160; // Signature field width int sigHeight = 45; // Signature field height string timeFormat = "hh:mm:ss"; // Time appearance format mask string dateFormat = "dd/MM/yyyy"; // Date appearance format mask int appearanceMask = (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_GRAPHICAL_IMAGE | // Elements to display on the signature field (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_SIGNED_BY | (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TIME; try { // Initialize SAPI library if ((rc = SAPI.Init()) != SAPI_OK) { throw new Exception(string.Format("Failed to initialize SAPI ({0})", rc.ToString("X"))); } // Acquire SAPI session handle if ((rc = SAPI.HandleAcquire(out sesHandle)) != SAPI_OK) { throw new Exception(string.Format("Failed in SAPIHandleAcquire() ({0})", rc.ToString("X"))); } // Personalize SAPI Session if ((rc = SAPI.Logon(sesHandle, username, domain, password)) != SAPI_OK) { throw new Exception(string.Format("Failed to authenticate user ({0})", rc.ToString("X"))); } SigFieldSettings SFS = new SigFieldSettings(); TimeFormat TF = new TimeFormat(); // Define signature field settings SFS.Page = sigPageNum; SFS.X = sigX; SFS.Y = sigY; SFS.Width = sigWidth; SFS.Height = sigHeight; SFS.AppearanceMask = appearanceMask; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; TF.DateFormat = dateFormat; TF.TimeFormat = timeFormat; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_GMT; // Display GMT offset SFS.TimeFormat = TF; // Create and sign a new signature field in the document if (SAPI_OK != (rc = SAPI.SignatureFieldCreateSign( sesHandle, // Session Handle SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, // Type of the file to sign - PDF filePath, // Path to PDF file to sign SFS, // Signature Field details 0, // Flags null))) // Credentials (only if prompt-for-sign feature is enabled) { throw new Exception(string.Format("Failed in SAPISignatureFieldCreateSign() ({0})", rc.ToString("X"))); } Console.WriteLine("The document has been successfully signed!"); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if (sesHandle != null) { SAPI.Logoff(sesHandle); // Release user context SAPI.HandleRelease(sesHandle); // Release session handle } } }
// This function is thread-safe and could be called by a few threads simoltaneously. // If FieldName parameter is NULL, a new field will be created, otherwise existing field will be signed // and all field-related parameters will be ignored public static void SAPI_sign_file(string FileName, string FieldName, string User, string Password, string SignPassword, int page, int x, int y, int height, int width, bool Invisible, string Reason, int AppearanceMask, string NewFieldName, string GraphImgName) { int rc; SESHandle SesHandle; SigFieldHandle sf = null; SAPICrypt SAPI = new SAPICrypt(); if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) { throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X")); } //Logon if ((rc = SAPI.Logon(SesHandle, User, null, Password)) != 0) { SAPI.HandleRelease(SesHandle); throw new Exception("Failed to authenticate user with rc = " + rc.ToString("X")); } //Set Graphical Image if required if (GraphImgName != null && GraphImgName.Length > 1) { SAPIContext ctxGraphImg = new SAPIContext(); //Start Graphical Images Enumeration if ((rc = SAPI.GraphicSigImageEnumInit(SesHandle, ctxGraphImg, AR_GR_SIG_DATA_FORMAT_ALL, 0)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to enumerate graphical signatures with rc = " + rc.ToString()); } GraphicImageHandle hGrImg = null; bool isFound = false; while (((uint)(rc = SAPI.GraphicSigImageEnumCont(SesHandle, ctxGraphImg, out hGrImg))) != SAPI_ERROR_NO_MORE_ITEMS) { if (rc != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve next graphical signature with rc = " + rc.ToString()); } //Get Graphical Signature Info GraphicImageInfo giInfo = null; if ((rc = SAPI.GraphicSigImageInfoGet(SesHandle, hGrImg, out giInfo, SAPI_ENUM_GRAPHIC_IMAGE_FORMAT.SAPI_ENUM_GRAPHIC_IMAGE_NONE, 0)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve graphical signature info with rc = " + rc.ToString()); } //Check if required Graphical image has been found if (giInfo.Name.Trim().ToLower() == GraphImgName.Trim().ToLower()) { //If found - set is as default Graph. Image if ((rc = SAPI.GraphicSigImageSetDefault(SesHandle, hGrImg)) != 0) { SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to define default graphical signature with rc = " + rc.ToString()); } isFound = true; SAPI.ContextRelease(ctxGraphImg); SAPI.HandleRelease(hGrImg); break; } SAPI.HandleRelease(hGrImg); } SAPI.ContextRelease(ctxGraphImg); //If required Graph Image wasn't found... if (!isFound) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to find Graphical Image with name: " + GraphImgName); } } //Create new signature field if (FieldName == null) { SigFieldSettings SFS = new SigFieldSettings(); TimeFormat TF = new TimeFormat(); int Flags = 0; //Define name of the new signature field if (NewFieldName.Length > 0) { SFS.Name = NewFieldName; Flags |= AR_PDF_FLAG_FIELD_NAME_SET; } if (Invisible) { SFS.Invisible = 1; SFS.Page = -1; } else { // VISIBLE: SFS.Invisible = 0; // location: SFS.Page = page; SFS.X = x; SFS.Y = y; SFS.Height = height; SFS.Width = width; // appearance: SFS.AppearanceMask = AppearanceMask; SFS.LabelsMask = AppearanceMask; SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT; SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL; SFS.Flags = 0; // time: TF.DateFormat = "dd MMM yyyy"; TF.TimeFormat = "hh:mm:ss"; TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_NONE; SFS.TimeFormat = TF; } //Create the Field if ((rc = SAPI.SignatureFieldCreate(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, SFS, Flags, out sf)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X")); } } //Find an existing signature field by name else { SAPIContext ctxField = new SAPIContext(); int NumOfFields = 0; //Initiate the Signature Fields enumeration process if ((rc = SAPI.SignatureFieldEnumInit(SesHandle, ctxField, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, FileName, 0, ref NumOfFields)) != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to start signature field enumeration with rc = " + rc.ToString("X")); } bool isFound = false; for (int i = 0; i < NumOfFields; i++) { //Get Next field's handle if ((rc = SAPI.SignatureFieldEnumCont(SesHandle, ctxField, out sf)) != 0) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in signature fields enumeration with rc = " + rc.ToString("X")); } //Retrieve Signature Field's info SigFieldSettings sfs = new SigFieldSettings(); SigFieldInfo sfi = new SigFieldInfo(); if ((rc = SAPI.SignatureFieldInfoGet(SesHandle, sf, sfs, sfi)) != 0) { SAPI.HandleRelease(sf); SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to retrieve signature field details with rc = " + rc.ToString("X")); } //Check that the field we've found is not signed. If Signed - just skip it. if (sfi.IsSigned != 0) { continue; } if (sfs.Name == FieldName) { SAPI.ContextRelease(ctxField); isFound = true; break; } //Release handle of irrelevant signature field SAPI.HandleRelease(sf); } if (!isFound) { SAPI.ContextRelease(ctxField); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("The file doesn't contain any signature field named: " + FieldName); } } //Define the Reason if ((rc = SAPI.ConfigurationValueSet(SesHandle, SAPI_ENUM_CONF_ID.SAPI_ENUM_CONF_ID_REASON, SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_STR, Reason, 1)) != 0) { SAPI.HandleRelease(sf); SAPI.Logoff(SesHandle); SAPI.HandleRelease(SesHandle); throw new Exception("Failed in SAPIConfigurationValueSet with rc = " + rc.ToString("X")); } if (string.IsNullOrEmpty(SignPassword)) { //Prompt-for-sign mode is disabled rc = SAPI.SignatureFieldSign(SesHandle, sf, 0); } else { //Prompt-for-sign mode is enabled rc = SAPI.SignatureFieldSignEx(SesHandle, sf, 0, SignPassword); } if (rc != 0) { SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); throw new Exception("Failed to Sign signature field with rc = " + rc.ToString("X")); } SAPI.Logoff(SesHandle); SAPI.HandleRelease(sf); SAPI.HandleRelease(SesHandle); return; }
public static void SignXML( string Username, string Domain, string Password, string XMLDataToSign //The stream to read the data to be signed from ) { if (string.IsNullOrEmpty(Username)) { throw new ArgumentNullException("Username"); } if (string.IsNullOrEmpty(Password)) { throw new ArgumentNullException("Password"); } if (XMLDataToSign == null) { throw new ArgumentNullException("XMLDataToSign"); } //Make sure the SAPI library is loaded into the current process SAPIInit(); //Instantiate SAPI object SAPICrypt SAPI = new SAPICrypt(); SigFieldSettings SFS = new SigFieldSettings(); SESHandle hSes = null; int rc = 0; if ((rc = SAPI.HandleAcquire(out hSes)) != 0) { throw new Exception(string.Format( "Memory allocation error (#{0})", rc.ToString("X"))); } if (Domain.Trim() == "") { rc = SAPI.Logon(hSes, Username, null, Password); } else { rc = SAPI.Logon(hSes, Username, Domain, Password); } if (rc != 0) { SAPI.HandleRelease(hSes); throw new Exception(string.Format( "Failed to authenticate the user(#{0})", rc.ToString("X"))); } if ((rc = SAPI.SignatureFieldCreateSignEx2(hSes, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_XML, XMLDataToSign, null, new SigFieldSettings(), AR_XML_XML_SIG_TYPE_ENVELOPED | AR_XML_SIG_TYPE_XADES_BES, null)) != 0) { SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); throw new Exception(string.Format( "Failed to initialize XML signing process(#{0})", rc.ToString("X"))); } //Cleanup memory SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); }
public static void SignStream( string Username, string Domain, string Password, Stream DataToSign, //The stream to read the data to be signed from Stream SignatureData //The stream to write the signature data to ) { if (string.IsNullOrEmpty(Username)) { throw new ArgumentNullException("Username"); } if (string.IsNullOrEmpty(Password)) { throw new ArgumentNullException("Password"); } if (DataToSign == null) { throw new ArgumentNullException("DataToSign"); } if (SignatureData == null) { throw new ArgumentNullException("SignatureData"); } //Make sure the SAPI library is loaded into the current process SAPIInit(); //Instantiate SAPI object SAPICrypt SAPI = new SAPICrypt(); SESHandle hSes = null; int rc = 0; if ((rc = SAPI.HandleAcquire(out hSes)) != 0) { throw new Exception(string.Format( "Memory allocation error (#{0})", rc.ToString("X"))); } if ((rc = SAPI.Logon(hSes, Username, Domain, Password)) != 0) { SAPI.HandleRelease(hSes); throw new Exception(string.Format( "Failed to authenticate the user(#{0})", rc.ToString("X"))); } //Allocate new signing context SAPIContext ctxBuffSign = new SAPIContext(); if ((rc = SAPI.BufferSignInit(hSes, ctxBuffSign, 0)) != 0) { SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); throw new Exception(string.Format( "Failed to initialize buffer signing process(#{0})", rc.ToString("X"))); } int remaining = (int)DataToSign.Length; //Check that the stream is not empty if ((int)DataToSign.Length < 1) { SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); throw new Exception("Cannot sign empty stream!"); } int chunkMaxSize = 1 << 20; //1MB //Calculate first chunk size int chunkSize = remaining < chunkMaxSize ? remaining : chunkMaxSize; while (remaining > 0) { Array chunk = new byte[chunkSize]; //Read in chunks of 1MB int read = DataToSign.Read((byte[])chunk, 0, chunkSize); if (read <= 0) { throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining)); } //Build SAPI-Compatible bytes array SAPIByteArray tmpBuff = new SAPIByteArray(); tmpBuff.FromArray(ref chunk); //Add read buffer to the signature calculation if ((rc = SAPI.BufferSignCont(hSes, ctxBuffSign, tmpBuff)) != 0) { SAPI.ContextRelease(ctxBuffSign); SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); throw new Exception(string.Format( "An error occured while calculating the digital signature (#{0})", rc.ToString("X"))); } remaining -= read; chunkSize = Math.Min(remaining, chunkSize); } SAPIByteArray signature = new SAPIByteArray(); //Get the final signature if ((rc = SAPI.BufferSignEnd(hSes, ctxBuffSign, signature)) != 0) { SAPI.ContextRelease(ctxBuffSign); SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); throw new Exception(string.Format( "Failed to sign the data (#{0})", rc.ToString("X"))); } //Write signature data to the stream byte[] tmpSig = (byte[])signature.ToArray(); SignatureData.Write(tmpSig, 0, tmpSig.Length); //Cleanup memory SAPI.ContextRelease(ctxBuffSign); SAPI.Logoff(hSes); SAPI.HandleRelease(hSes); }