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 SAPICryptClass();
            SigFieldSettings SFS = new SigFieldSettingsClass();

            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 SigFieldSettingsClass(), 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);
        }
        //Thread-Safe SAPIInit()
        private static void SAPIInit()
        {
            SAPICrypt SAPI = new SAPICryptClass();

            lock (_SyncRoot)
            {
                //Do nothing if SAPI is initialized already
                if (isSAPIInitialized(SAPI))
                {
                    return;
                }


                //Initialize SAPI
                int rc = SAPI.Init();
                if (rc != 0)
                {
                    throw new Exception(string.Format(
                                            "Failed to load SAPI library (#{0})", rc.ToString("X")));
                }
            }
        }
        static void Main(string[] args)
        {
            const int SAPI_OK = 0;

            int       rc;
            SAPICrypt SAPI      = new SAPICryptClass();
            SESHandle sesHandle = null;

            // Custom Values
            string filePath       = @"c:\temp\demo.pdf";                                                       // PDF file to sign
            string username       = "******";                                                       // CoSign account username
            string password       = "******";                                                       // CoSign account password
            string domain         = null;                                                                      // CoSign 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")));
                }

                SigFieldSettingsClass SFS = new SigFieldSettingsClass();
                TimeFormatClass       TF  = new TimeFormatClass();

                // 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
                }
            }
        }
        static void Main(string[] args)
        {
            string InFileName = "C:\\temp\\tag-sample.pdf";
            string OutFileName = "C:\\temp\\tag-sample-signed.pdf";
            string startDelim = "<<";
            string endDelim = ">>";
            int rc;
            SESHandle SesHandle;
            SigFieldSettingsClass SFS = new SigFieldSettingsClass();
            TimeFormatClass TF = new TimeFormatClass();
            int Flags = AR_PDF_FLAG_FIELD_NAME_SET;
            int LocNumber;

            SAPICrypt SAPI = new SAPICryptClass();

            // SAPIInit() should be called once per process
            if ((rc = SAPI.Init()) != 0) throw new Exception("Failed to initialize SAPI! (" + rc.ToString("X") + ")");

            // Open a new SAPI context
            if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0) throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X"));

            if ((rc = SAPI.Logon(SesHandle, "testuser", null, "12345678")) != 0)
            {
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed in SAPILogon() with rc = " + rc.ToString("X"));
            }

            //
            // Locate all field tags in the PDF
            // The PDF filename to be used is defined above.
            // The format of each field locator in the PDF should be:
            //   << w={width}; h={height}; n={field name}; a={appearance mask} >>
            //
            // For example:
            //  << w=120; h=80; n=Signer1; a=15; >>
            //
            SAPIContext SigLocatorCtx = new SAPIContext();

            Array fileBytes = File.ReadAllBytes(InFileName);
            SAPIByteArray doc = new SAPIByteArrayClass();
            doc.FromArray(ref fileBytes);
            FileHandle fh;
            if ((rc = SAPI.CreateFileHandleByMem(out fh, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, 0, doc)) != 0)
            {
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed to create file handle with rc = " + rc.ToString("X"));
            }

            //  Initiate a new Field Locator enumerator.
            //  The argument LocNumber will contain the number of signature tags found in the PDF document.
            //
            if ((rc = SAPI.SignatureFieldLocatorEnumInit(SesHandle, SigLocatorCtx, fh, startDelim, endDelim, 0, out LocNumber)) != 0)
            {
                SAPI.HandleRelease(fh);
                SAPI.HandleRelease(SesHandle);
                throw new Exception("LocatorEnumInit failed with rc = " + rc.ToString("X"));
            }

            // Do for all tags in the document
            string strEncMsg;
            for (int i = 0; i < LocNumber; i++)
            {
                // Get settings for the next field locator.
                // (Use strEncMsg string to parse the field locator content if a custom string format has been used)
                if ((rc = SAPI.SignatureFieldLocatorEnumCont(SesHandle, SigLocatorCtx, SFS, out strEncMsg)) != 0)
                {
                    SAPI.ContextRelease(SigLocatorCtx);
                    SAPI.HandleRelease(fh);
                    SAPI.HandleRelease(SesHandle);
                    throw new Exception("LocatorEnumCont failed with rc = " + rc.ToString("X"));
                }

                // The following values of the SignatureFieldSettings will be automatically set by SAPI:
                //   X/Y Location (including page number)
                //   Width
                //   Height
                //   Field Name
                //   Appearance Mask
                //
                SFS.LabelsMask = 0;
                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;

                //  Now create the signature field on the PDF
                //  We make use of SignatureFieldCreateEx function in order to pass the FileHandle for the in-memory
                //  file rather than a UNC file path.
                if ((rc = SAPI.SignatureFieldCreateSignEx2(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE,
                    "", fh, SFS, Flags, null)) != 0)
                {
                    SAPI.ContextRelease(SigLocatorCtx);
                    SAPI.HandleRelease(fh);
                    SAPI.HandleRelease(SesHandle);
                    throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X"));
                }
            }

            //  Write the PDF to an output file
            if ((rc = SAPI.GetFileMemData(fh, 0, doc)) != 0)
            {
                SAPI.ContextRelease(SigLocatorCtx);
                SAPI.HandleRelease(fh);
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed to GetFileMem with rc = " + rc.ToString("X"));
            }

            File.WriteAllBytes(OutFileName, (byte[])doc.ToArray());

            //  Finalize work with SAPI
            SAPI.ContextRelease(SigLocatorCtx);
            SAPI.HandleRelease(fh);
            SAPI.HandleRelease(SesHandle);
        }
Esempio n. 5
0
        static void Main(string[] args)
        {
            string                InFileName  = "C:\\temp\\tag-sample.pdf";
            string                OutFileName = "C:\\temp\\tag-sample-signed.pdf";
            string                startDelim  = "<<";
            string                endDelim    = ">>";
            int                   rc;
            SESHandle             SesHandle;
            SigFieldSettingsClass SFS   = new SigFieldSettingsClass();
            TimeFormatClass       TF    = new TimeFormatClass();
            int                   Flags = AR_PDF_FLAG_FIELD_NAME_SET;
            int                   LocNumber;

            SAPICrypt SAPI = new SAPICryptClass();

            // SAPIInit() should be called once per process
            if ((rc = SAPI.Init()) != 0)
            {
                throw new Exception("Failed to initialize SAPI! (" + rc.ToString("X") + ")");
            }

            // Open a new SAPI context
            if ((rc = SAPI.HandleAcquire(out SesHandle)) != 0)
            {
                throw new Exception("Failed in SAPIHandleAcquire() with rc = " + rc.ToString("X"));
            }

            if ((rc = SAPI.Logon(SesHandle, "testuser", null, "12345678")) != 0)
            {
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed in SAPILogon() with rc = " + rc.ToString("X"));
            }

            //
            // Locate all field tags in the PDF
            // The PDF filename to be used is defined above.
            // The format of each field locator in the PDF should be:
            //   << w={width}; h={height}; n={field name}; a={appearance mask} >>
            //
            // For example:
            //  << w=120; h=80; n=Signer1; a=15; >>
            //
            SAPIContext SigLocatorCtx = new SAPIContext();

            Array         fileBytes = File.ReadAllBytes(InFileName);
            SAPIByteArray doc       = new SAPIByteArrayClass();

            doc.FromArray(ref fileBytes);
            FileHandle fh;

            if ((rc = SAPI.CreateFileHandleByMem(out fh, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, 0, doc)) != 0)
            {
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed to create file handle with rc = " + rc.ToString("X"));
            }

            //  Initiate a new Field Locator enumerator.
            //  The argument LocNumber will contain the number of signature tags found in the PDF document.
            //
            if ((rc = SAPI.SignatureFieldLocatorEnumInit(SesHandle, SigLocatorCtx, fh, startDelim, endDelim, 0, out LocNumber)) != 0)
            {
                SAPI.HandleRelease(fh);
                SAPI.HandleRelease(SesHandle);
                throw new Exception("LocatorEnumInit failed with rc = " + rc.ToString("X"));
            }

            // Do for all tags in the document
            string strEncMsg;

            for (int i = 0; i < LocNumber; i++)
            {
                // Get settings for the next field locator.
                // (Use strEncMsg string to parse the field locator content if a custom string format has been used)
                if ((rc = SAPI.SignatureFieldLocatorEnumCont(SesHandle, SigLocatorCtx, SFS, out strEncMsg)) != 0)
                {
                    SAPI.ContextRelease(SigLocatorCtx);
                    SAPI.HandleRelease(fh);
                    SAPI.HandleRelease(SesHandle);
                    throw new Exception("LocatorEnumCont failed with rc = " + rc.ToString("X"));
                }

                // The following values of the SignatureFieldSettings will be automatically set by SAPI:
                //   X/Y Location (including page number)
                //   Width
                //   Height
                //   Field Name
                //   Appearance Mask
                //
                SFS.LabelsMask     = 0;
                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;

                //  Now create the signature field on the PDF
                //  We make use of SignatureFieldCreateEx function in order to pass the FileHandle for the in-memory
                //  file rather than a UNC file path.
                if ((rc = SAPI.SignatureFieldCreateSignEx2(SesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE,
                                                           "", fh, SFS, Flags, null)) != 0)
                {
                    SAPI.ContextRelease(SigLocatorCtx);
                    SAPI.HandleRelease(fh);
                    SAPI.HandleRelease(SesHandle);
                    throw new Exception("Failed to create new signature field with rc = " + rc.ToString("X"));
                }
            }

            //  Write the PDF to an output file
            if ((rc = SAPI.GetFileMemData(fh, 0, doc)) != 0)
            {
                SAPI.ContextRelease(SigLocatorCtx);
                SAPI.HandleRelease(fh);
                SAPI.HandleRelease(SesHandle);
                throw new Exception("Failed to GetFileMem with rc = " + rc.ToString("X"));
            }

            File.WriteAllBytes(OutFileName, (byte[])doc.ToArray());

            //  Finalize work with SAPI
            SAPI.ContextRelease(SigLocatorCtx);
            SAPI.HandleRelease(fh);
            SAPI.HandleRelease(SesHandle);
        }
        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 SAPICryptClass();
            SigFieldSettings SFS  = new SigFieldSettingsClass();

            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 SigFieldSettingsClass(), 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 SignatureDetails ValidateXMLSignature(string SignedXML)
        {
            if (SignedXML == null)
            {
                throw new ArgumentNullException("SignedXML");
            }

            //Make sure the SAPI Library is loaded
            SAPIInit();
            SignatureDetails SigDetails         = new SignatureDetails();
            SigFieldSettings SigFieldSettings   = new SigFieldSettingsClass();
            SigFieldInfo     SignatureFieldInfo = new SigFieldInfoClass();
            SAPICrypt        SAPI   = new SAPICryptClass();
            SigFieldHandle   hField = null;
            int rc;

            SESHandle hSession = new SESHandleClass();

            if ((rc = SAPI.HandleAcquire(out hSession)) != 0)
            {
                throw new Exception(string.Format(
                                        "Memory allocation error (#{0})", rc.ToString("X")));
            }

            SAPIContext ctxValidateSignature = new SAPIContextClass();
            int         num = 0;

            if ((rc = SAPI.SignatureFieldEnumInit(hSession, ctxValidateSignature, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_XML, SignedXML, 0, ref num)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                                        "An error occured while initializing the signature validation process (#{0})", rc.ToString("X")));
            }

            if (num < 1)
            {
                throw new Exception("The XML file is not signed!");
            }
            if (num > 1)
            {
                throw new Exception("SAPI only supports a single signature per XML file!");
            }

            if ((rc = SAPI.SignatureFieldEnumCont(hSession, ctxValidateSignature, out hField)) != 0)
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                                        "Failed to retrieve signature (#{0})", rc.ToString("X")));
            }

            if ((rc = SAPI.SignatureFieldInfoGet(hSession, hField, SigFieldSettings, SignatureFieldInfo)) != 0)
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                                        "Failed to parse signature details (#{0})", rc.ToString("X")));
            }

            CertStatus not_used = new CertStatus();

            SigDetails.isValid = SAPI.SignatureFieldVerify(hSession, hField, not_used, 0) == 0;

            SigDetails.SignerCertificate = new X509Certificate2(
                (byte[])(((SAPIByteArray)SignatureFieldInfo.Certificate).ToArray()));
            SigDetails.SignerName = SignatureFieldInfo.SignerName;

            //Convert FILE_TIME to ticks
            ulong filetime = SignatureFieldInfo.SignatureTime.HighDateTime;

            filetime <<= 32;
            filetime  += SignatureFieldInfo.SignatureTime.LowDateTime;
            SigDetails.SignatureTimeTicks = DateTime.FromFileTimeUtc((long)filetime).Ticks;

            //Cleanup memory
            SAPI.ContextRelease(ctxValidateSignature);
            SAPI.HandleRelease(hSession);

            return(SigDetails);
        }
        // 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 SAPICryptClass();

            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 SAPIContextClass();

                //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)
            {
                SigFieldSettingsClass SFS = new SigFieldSettingsClass();
                TimeFormatClass TF = new TimeFormatClass();
                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 SAPIContextClass();
                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 SigFieldSettingsClass();
                    SigFieldInfo sfi = new SigFieldInfoClass();
                    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;
        }
 //SAPIInit() should be called in the static constructor in order to make sure
 //that it's called only once, when the class is being initialized.
 static FileSign()
 {
     SAPICrypt SAPI = new SAPICryptClass();
     int rc = SAPI.Init(); //SAPIInit() should be called once per process
     if (rc != 0) throw new Exception("Failed to initialize SAPI! (" + rc.ToString("X") + ")");
 }
        public static SignatureDetails ValidateXMLSignature(string SignedXML)
        {
            if (SignedXML == null) throw new ArgumentNullException("SignedXML");

            //Make sure the SAPI Library is loaded
            SAPIInit();
            SignatureDetails SigDetails = new SignatureDetails();
            SigFieldSettings SigFieldSettings = new SigFieldSettingsClass();
            SigFieldInfo SignatureFieldInfo = new SigFieldInfoClass();
            SAPICrypt SAPI = new SAPICryptClass();
            SigFieldHandle hField = null;
            int rc;

            SESHandle hSession = new SESHandleClass();
            if ((rc = SAPI.HandleAcquire(out hSession)) != 0)
            {
                throw new Exception(string.Format(
                    "Memory allocation error (#{0})", rc.ToString("X")));
            }

            SAPIContext ctxValidateSignature = new SAPIContextClass();
            int num = 0;
            if ((rc = SAPI.SignatureFieldEnumInit(hSession, ctxValidateSignature, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_XML, SignedXML, 0, ref num)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                    "An error occured while initializing the signature validation process (#{0})", rc.ToString("X")));
            }

            if (num < 1) throw new Exception("The XML file is not signed!");
            if (num > 1) throw new Exception("SAPI only supports a single signature per XML file!");

            if ((rc = SAPI.SignatureFieldEnumCont(hSession, ctxValidateSignature, out hField)) != 0)
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                    "Failed to retrieve signature (#{0})", rc.ToString("X")));
            }

            if ((rc = SAPI.SignatureFieldInfoGet(hSession, hField, SigFieldSettings, SignatureFieldInfo)) != 0)
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                    "Failed to parse signature details (#{0})", rc.ToString("X")));
            }

            CertStatus not_used = new CertStatus();
            SigDetails.isValid = SAPI.SignatureFieldVerify(hSession, hField, not_used, 0) == 0;

            SigDetails.SignerCertificate = new X509Certificate2(
                (byte[])(((SAPIByteArray)SignatureFieldInfo.Certificate).ToArray()));
            SigDetails.SignerName = SignatureFieldInfo.SignerName;

            //Convert FILE_TIME to ticks
            ulong filetime = SignatureFieldInfo.SignatureTime.HighDateTime;
            filetime <<= 32;
            filetime += SignatureFieldInfo.SignatureTime.LowDateTime;
            SigDetails.SignatureTimeTicks = DateTime.FromFileTimeUtc((long)filetime).Ticks;

            //Cleanup memory
            SAPI.ContextRelease(ctxValidateSignature);
            SAPI.HandleRelease(hSession);

            return SigDetails;
        }
        //Thread-Safe SAPIInit()
        private static void SAPIInit()
        {
            SAPICrypt SAPI = new SAPICryptClass();

            lock (_SyncRoot)
            {
                //Do nothing if SAPI is initialized already
                if (isSAPIInitialized(SAPI)) return;

                //Initialize SAPI
                int rc = SAPI.Init();
                if (rc != 0)
                {
                    throw new Exception(string.Format(
                        "Failed to load SAPI library (#{0})", rc.ToString("X")));
                }
            }
        }
        public static void SignPDF(
            string filePath,
            string username,
            string domain,
            string password,
            int sigPageNum,
            int sigX,
            int sigY,
            int sigWidth,
            int sigHeight,
            string title)
        {
            const int SAPI_OK = 0;
            const int AR_PDF_FLAG_FILESIGN_VERTICAL = 0x00000020;

            int rc;
            SAPICrypt SAPI = new SAPICryptClass();
            SESHandle sesHandle = null;
            GraphicImageHandle grpImgHandle = null;

            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")));
                }

                // If the user has more than one graphical signatures, this function opens a new dialog window enabling the user to view and select an image with which to sign.
                if ((rc = SAPI.GraphicSigImageGUISelect(sesHandle, (int)0xFF, 0, SAPI_ENUM_GR_IMG_SELECT_MODE.SAPI_ENUM_GR_IMG_SEL_MODE_SELECT, out grpImgHandle)) != SAPI_OK)
                {
                    throw new Exception(string.Format("Failed in SAPIGraphicSigImageGUISelect() ({0})", rc.ToString("X")));
                }

                // Set the graphical image associated with the graphic image handle as the default graphic signature image
                if ((rc = SAPI.GraphicSigImageSetDefaultEx(sesHandle, grpImgHandle, 0)) != SAPI_OK)
                {
                    throw new Exception(string.Format("Failed in SAPIGraphicSigImageSetDefaultEx() ({0})", rc.ToString("X")));
                }

                SigFieldSettingsClass SFS = new SigFieldSettingsClass();
                TimeFormatClass TF = new TimeFormatClass();

                // Define signature field settings
                SFS.Page = sigPageNum;
                SFS.X = sigX;
                SFS.Y = sigY;
                SFS.Width = sigWidth;
                SFS.Height = sigHeight;
                SFS.AppearanceMask = (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_GRAPHICAL_IMAGE |
                                     (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_SIGNED_BY |
                                     (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TIME;
                SFS.SignatureType = SAPI_ENUM_SIGNATURE_TYPE.SAPI_ENUM_SIGNATURE_DIGITAL;
                SFS.DependencyMode = SAPI_ENUM_DEPENDENCY_MODE.SAPI_ENUM_DEPENDENCY_MODE_INDEPENDENT;
                TF.DateFormat = "dd/MM/yyyy";
                TF.TimeFormat = "hh:mm:ss";
                TF.ExtTimeFormat = SAPI_ENUM_EXTENDED_TIME_FORMAT.SAPI_ENUM_EXTENDED_TIME_FORMAT_GMT; // Display GMT offset
                SFS.TimeFormat = TF;

                if (!string.IsNullOrEmpty(title))
                {
                    // Set signer's title
                    if ((rc = SAPI.ConfigurationValueSet(sesHandle, SAPI_ENUM_CONF_ID.SAPI_ENUM_CONF_ID_TITLE, SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_WSTR, title, 1)) != SAPI_OK)
                    {
                        throw new Exception(string.Format("Failed in SAPIConfigurationValueSet() ({0})", rc.ToString("X")));
                    }

                    SFS.AppearanceMask |= (int)SAPI_ENUM_DRAWING_ELEMENT.SAPI_ENUM_DRAWING_ELEMENT_TITLE;
                }

                // Create and sign a new signature field in the document
                if (SAPI_OK != (rc = SAPI.SignatureFieldCreateSign(sesHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_ADOBE, filePath, SFS, AR_PDF_FLAG_FILESIGN_VERTICAL, null)))
                {
                    throw new Exception(string.Format("Failed in SAPISignatureFieldCreateSign() ({0})", rc.ToString("X")));
                }
            }
            catch (Exception ex)
            {
                if (sesHandle != null)
                {
                    SAPI.Logoff(sesHandle);         // Release user context
                    SAPI.HandleRelease(sesHandle);  // Release session handle
                }

                if (grpImgHandle != null)
                {
                    SAPI.HandleRelease(grpImgHandle);
                }

                throw ex;
            }
        }
Esempio n. 13
0
        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 SAPICryptClass();

            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 SAPIContextClass();

            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 SAPIByteArrayClass();
                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 SAPIByteArrayClass();

            //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);
        }
Esempio n. 14
0
        public static SignatureDetails ValidateSignature(Stream SignedData, Stream Signature)
        {
            if (SignedData == null)
            {
                throw new ArgumentNullException("SignedData");
            }
            if (Signature == null)
            {
                throw new ArgumentNullException("Signature");
            }

            //Make sure the SAPI Library is loaded
            SAPIInit();

            SignatureDetails SigDetails = new SignatureDetails();
            int rc;

            SAPICrypt SAPI = new SAPICryptClass();

            SESHandle hSession = new SESHandleClass();

            if ((rc = SAPI.HandleAcquire(out hSession)) != 0)
            {
                throw new Exception(string.Format(
                                        "Memory allocation error (#{0})", rc.ToString("X")));
            }



            //Extract Signer Data from the Signature stream



            //Read Signature content from stream to the SAPI bytes array
            Array baSignature = new byte[(int)Signature.Length];

            Signature.Read((byte[])baSignature, 0, (int)Signature.Length);
            SAPIByteArray sSignature = new SAPIByteArrayClass();

            sSignature.FromArray(ref baSignature);

            //SAPIByteArray sSignedData = new SAPIByteArrayClass();
            //Array t1 = (Array)SignedData; sSignedData.FromArray(ref t1);


            object Certificate;
            // Extract the signer's certificate from signature
            SAPI_ENUM_DATA_TYPE SAPIType = SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_NONE;

            if ((rc = SAPI.PKCS7BlobGetValue(hSession, sSignature, SAPI_ENUM_PKCS7_FIELD.SAPI_ENUM_PKCS7_FIELD_CERT, out Certificate, ref SAPIType)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                                        "An error occured while extracting the signer's certificate from the signature stream (#{0})", rc.ToString("X")));
            }

            SigDetails.SignerCertificate = new X509Certificate2((byte[])(((SAPIByteArray)Certificate).ToArray()));
            SigDetails.SignerName        = SigDetails.SignerCertificate.GetNameInfo(X509NameType.SimpleName, false);
            SigDetails.SignerEmail       = SigDetails.SignerCertificate.GetNameInfo(X509NameType.EmailName, false);


            //Run the signature validation process
            SAPIContext ctxValidateSignature = new SAPIContextClass();

            if ((rc = SAPI.BufferVerifySignatureInit(hSession,
                                                     ctxValidateSignature, sSignature, 0)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                                        "An error occured while initializing the signature validation process (#{0})", rc.ToString("X")));
            }


            int remaining    = (int)SignedData.Length;
            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  = SignedData.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 byte array
                SAPIByteArray tmpBuff = new SAPIByteArrayClass();
                tmpBuff.FromArray(ref chunk);

                //Add read buffer to the validation calculation
                if ((rc = SAPI.BufferVerifySignatureCont(hSession, ctxValidateSignature, tmpBuff)) != 0)
                {
                    SAPI.ContextRelease(ctxValidateSignature);
                    SAPI.HandleRelease(hSession);

                    throw new Exception(string.Format(
                                            "An error occured while validating the digital signature (#{0})", rc.ToString("X")));
                }

                remaining -= read;
                chunkSize  = Math.Min(remaining, chunkSize);
            }


            //Get the final validation result
            SAPIFileTime signingTime = new SAPIFileTimeClass();

            rc = SAPI.BufferVerifySignatureEnd(hSession, ctxValidateSignature, signingTime, new CertStatusClass());
            if ((uint)rc == 0x90030360)  //SAPI_SIGNATURE_NOT_VALID
            {
                SigDetails.isValid            = false;
                SigDetails.SignatureTimeTicks = 0;
            }
            else if (rc == 0)
            {
                SigDetails.isValid = true;

                //Convert FILE_TIME to ticks
                ulong filetime = signingTime.HighDateTime;
                filetime <<= 32;
                filetime  += signingTime.LowDateTime;
                SigDetails.SignatureTimeTicks = DateTime.FromFileTimeUtc((long)filetime).Ticks;
            }
            else
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);

                throw new Exception(string.Format(
                                        "Failed to validate Digital Signature (#{0})", rc.ToString("X")));
            }


            //Cleanup memory
            SAPI.ContextRelease(ctxValidateSignature);
            SAPI.HandleRelease(hSession);

            return(SigDetails);
        }
        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 SAPICryptClass();

            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 SAPIContextClass();

            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 SAPIByteArrayClass();
                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 SAPIByteArrayClass();

            //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);
        }
        public static SignatureDetails ValidateSignature(Stream SignedData, Stream Signature)
        {
            if (SignedData == null) throw new ArgumentNullException("SignedData");
            if (Signature == null) throw new ArgumentNullException ("Signature");

            //Make sure the SAPI Library is loaded
            SAPIInit();

            SignatureDetails SigDetails = new SignatureDetails();
            int rc;

            SAPICrypt SAPI = new SAPICryptClass();

            SESHandle hSession = new SESHandleClass();
            if ((rc = SAPI.HandleAcquire(out hSession)) != 0)
            {
                throw new Exception(string.Format(
                    "Memory allocation error (#{0})", rc.ToString("X")));
            }

            //Extract Signer Data from the Signature stream

            //Read Signature content from stream to the SAPI bytes array
            Array baSignature = new byte[(int)Signature.Length];
            Signature.Read((byte[])baSignature, 0, (int)Signature.Length);
            SAPIByteArray sSignature = new SAPIByteArrayClass();
            sSignature.FromArray(ref baSignature);

            //SAPIByteArray sSignedData = new SAPIByteArrayClass();
            //Array t1 = (Array)SignedData; sSignedData.FromArray(ref t1);

            object Certificate;
            // Extract the signer's certificate from signature
            SAPI_ENUM_DATA_TYPE SAPIType = SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_NONE;
            if ((rc = SAPI.PKCS7BlobGetValue(hSession, sSignature, SAPI_ENUM_PKCS7_FIELD.SAPI_ENUM_PKCS7_FIELD_CERT, out Certificate, ref SAPIType)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                    "An error occured while extracting the signer's certificate from the signature stream (#{0})", rc.ToString("X")));
            }

            SigDetails.SignerCertificate = new X509Certificate2((byte[])(((SAPIByteArray)Certificate).ToArray()));
            SigDetails.SignerName = SigDetails.SignerCertificate.GetNameInfo (X509NameType.SimpleName, false);
            SigDetails.SignerEmail = SigDetails.SignerCertificate.GetNameInfo (X509NameType.EmailName, false);

            //Run the signature validation process
            SAPIContext ctxValidateSignature = new SAPIContextClass();

            if ((rc = SAPI.BufferVerifySignatureInit (hSession,
                ctxValidateSignature, sSignature, 0)) != 0)
            {
                SAPI.HandleRelease(hSession);
                throw new Exception(string.Format(
                    "An error occured while initializing the signature validation process (#{0})", rc.ToString("X")));
            }

            int remaining = (int) SignedData.Length;
            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 = SignedData.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 byte array
                SAPIByteArray tmpBuff = new SAPIByteArrayClass();
                tmpBuff.FromArray(ref chunk);

                //Add read buffer to the validation calculation
                if ((rc = SAPI.BufferVerifySignatureCont(hSession, ctxValidateSignature, tmpBuff)) != 0)
                {
                    SAPI.ContextRelease(ctxValidateSignature);
                    SAPI.HandleRelease(hSession);

                    throw new Exception(string.Format(
                        "An error occured while validating the digital signature (#{0})", rc.ToString("X")));
                }

                remaining -= read;
                chunkSize = Math.Min(remaining, chunkSize);
            }

            //Get the final validation result
            SAPIFileTime signingTime = new SAPIFileTimeClass();

            rc = SAPI.BufferVerifySignatureEnd(hSession, ctxValidateSignature, signingTime, new CertStatusClass());
            if ((uint)rc == 0x90030360)  //SAPI_SIGNATURE_NOT_VALID
            {
                SigDetails.isValid = false;
                SigDetails.SignatureTimeTicks = 0;
            }
            else if (rc == 0)
            {
                SigDetails.isValid  = true;

                //Convert FILE_TIME to ticks
                ulong filetime = signingTime.HighDateTime;
                filetime <<= 32;
                filetime += signingTime.LowDateTime;
                SigDetails.SignatureTimeTicks = DateTime.FromFileTimeUtc((long)filetime).Ticks;
            }
            else
            {
                SAPI.ContextRelease(ctxValidateSignature);
                SAPI.HandleRelease(hSession);

                throw new Exception(string.Format(
                    "Failed to validate Digital Signature (#{0})", rc.ToString("X")));
            }

            //Cleanup memory
            SAPI.ContextRelease(ctxValidateSignature);
            SAPI.HandleRelease(hSession);

            return SigDetails;
        }