// Copyright (C) 2003-2026, Foxit Software Inc..
// All Rights Reserved.
//
// http://www.foxitsoftware.com
//
// The following code is copyrighted and contains proprietary information and trade secrets of Foxit Software Inc..
// You cannot distribute any part of Foxit PDF SDK to any third party or general public,
// unless there is a separate license agreement with Foxit Software Inc. which explicitly grants you such rights.
//
// This file contains an example to demonstrate how to use Foxit PDF SDK to add, sign and
// verify signature in PDF document.

using System;
using System.Text;
using System.IO;
using foxit.common;
using foxit.pdf;
using foxit;
using foxit.pdf.annots;
using foxit.common.fxcrt;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography;
using foxit.pdf.interform;

namespace signatureCS
{
    class SignAndVerifyMsg {
        public static bool SignMsg(byte[] to_be_signed_data, string keyFile, string password, ref byte[] signed_data) {
            byte[] pfx_cert = File.ReadAllBytes(keyFile);

            SecureString pwd = new SecureString();
            char[] pwd_char_array = password.ToCharArray();
            for (int i = 0; i < pwd_char_array.Length; i++)
                pwd.AppendChar(pwd_char_array[i]);

            X509Certificate2 cert = new X509Certificate2(pfx_cert, pwd);
            CmsSigner signer = new CmsSigner(cert);
            signer.DigestAlgorithm = new Oid("1.3.14.3.2.26", "sha1");

            signer.IncludeOption = X509IncludeOption.WholeChain;

            ContentInfo signedData = new ContentInfo(to_be_signed_data);
            SignedCms cms = new SignedCms(signedData, false);
            cms.ComputeSignature(signer);
            signed_data = cms.Encode();

            return true;
        }

        public static bool VerifyMsg(byte[] verify_data, byte[] signed_data,
                String key_file) {
            Boolean b = true;
            try
            {
                ContentInfo signedData = new ContentInfo(verify_data);
                SignedCms cms = new SignedCms(signedData, false);
                cms.Decode(signed_data);
                // Check Signature
                cms.CheckSignature(true);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                b = false;
            }
            return b;
        }
    }


    // Used for implementing SignatureCallback.
    class DigestContext {
       public FileReaderCallback file_read_callback_;
       public System.IntPtr byte_range_array_;
       public int byte_range_array_size_;

       public DigestContext(FileReaderCallback file_read_callback, System.IntPtr byte_range_array, int byte_range_array_size)
       {
           this.file_read_callback_ = file_read_callback;
           this.byte_range_array_ = byte_range_array;
           this.byte_range_array_size_ = byte_range_array_size;
       }
    };

    // Implementation of pdf::SignatureCallback
    class SignatureCallbackImpl : SignatureCallback { 
        private DigestContext digest_context_ = null;
        byte[] arrall = null;

        public SignatureCallbackImpl() { 
        }

        public override bool StartCalcDigest(FileReaderCallback file, System.IntPtr byte_range_array, int size_of_array, Signature signature, IntPtr client_data) {
            digest_context_ = new DigestContext(file, byte_range_array, size_of_array);
            return true;
        }

        public override Progressive.State ContinueCalcDigest(IntPtr client_data, PauseCallback pause) {
            FileReaderCallback filehandler = digest_context_.file_read_callback_;
            int[] int_array = new int[digest_context_.byte_range_array_size_];
            Marshal.Copy(digest_context_.byte_range_array_, int_array, 0, digest_context_.byte_range_array_size_);

            byte[] arr1 = new byte[int_array[1]];
            IntPtr buffer1 = Marshal.AllocHGlobal(int_array[1]);

            filehandler.ReadBlock(buffer1,
                    int_array[0],
                    (uint)int_array[1]);

            Marshal.Copy(buffer1, arr1, 0, int_array[1]);

            byte[] arr2 = new byte[int_array[3]];
            IntPtr buffer2 = Marshal.AllocHGlobal(int_array[3]);
            filehandler.ReadBlock(buffer2,
                    int_array[2],
                    (uint)int_array[3]);
            Marshal.Copy(buffer2, arr2, 0, int_array[3]);

            byte[] arrall_temp = new byte[(int)int_array[1]
                    + (int)int_array[3]];
            Array.Copy(arr1, 0, arrall_temp, 0, arr1.Length);
            Array.Copy(arr2, 0, arrall_temp, arr1.Length, arr2.Length);

            Marshal.FreeHGlobal(buffer1);
            Marshal.FreeHGlobal(buffer2);

            HashAlgorithm hash = HashAlgorithm.Create("sha1");
            hash.Initialize();
            arrall = hash.ComputeHash(arrall_temp);
            
            return Progressive.State.e_Finished;
        }

        public override byte[] GetDigest(IntPtr client_data)
        {
            if (arrall != null)
            {
                return arrall;
            }
            return null;
        }

        public override byte[] Sign(IntPtr digest, int digest_length, string cert_path, byte[] password, Signature.DigestAlgorithm digest_algorithm, IntPtr client_data)
        {
            byte[] byte_digest = new byte[digest_length];
            Marshal.Copy(digest, byte_digest, 0, digest_length);

            byte[] encryptStr = null;
            SignAndVerifyMsg.SignMsg(byte_digest, signature.input_path + "foxit_all.pfx", "123456", ref encryptStr);
            return encryptStr;
        }

        public override byte[] Sign(IntPtr digest, int digest_length, StreamCallback cert_path, byte[] password, Signature.DigestAlgorithm digest_algorithm, IntPtr client_data)
        {
            return null;
        }
		
        public override uint VerifySigState(global::System.IntPtr digest, int digest_length, global::System.IntPtr signed_data, int signed_data_len, global::System.IntPtr client_data)
        {
            byte[] byte_signdata = new byte[signed_data_len];
            Marshal.Copy(signed_data, byte_signdata, 0 , signed_data_len);

            byte[] byte_digest = new byte[digest_length];
            Marshal.Copy(digest, byte_digest, 0, digest_length);

            bool verified = SignAndVerifyMsg.VerifyMsg(byte_digest, byte_signdata,
                     signature.input_path + "foxit.cer");

            return verified ? Convert.ToUInt32(Signature.States.e_StateVerifyNoChange) : Convert.ToUInt32(Signature.States.e_StateVerifyChange);
        }

        public override void Dispose()
        {
        }

        public override void Release()
        {
        }

        public override bool IsNeedPadData() {return false;}
        
        public override SignatureCallback.CertValidity CheckCertificateValidity(string cert_path, byte[] cert_password, global::System.IntPtr client_data) {
            // User can check the validity of input certificate here.
            // If no need to check, just return e_CertValid.
            return SignatureCallback.CertValidity.e_CertValid;
        }
    }
    class signature
    {
        public const string input_path = "../input_files/";
        public const string output_directory = "../output_files/signature/";

        static foxit.common.DateTime GetLocalDateTime()
        {
            System.DateTimeOffset rime = System.DateTimeOffset.Now;
            foxit.common.DateTime datetime = new foxit.common.DateTime();
            datetime.year = (UInt16)rime.Year;
            datetime.month = (UInt16)rime.Month;
            datetime.day = (ushort)rime.Day;
            datetime.hour = (UInt16)rime.Hour;
            datetime.minute = (UInt16)rime.Minute;
            datetime.second = (UInt16)rime.Second;
            datetime.utc_hour_offset = (short)rime.Offset.Hours;
            datetime.utc_minute_offset = (ushort)rime.Offset.Minutes;
            return datetime;
        }

        static string DateTimeToString(foxit.common.DateTime datetime) {
            string ret_string = String.Format("{0}/{1}/{2}-{3}:{4}:{5} {6}{7}:{8}", datetime.year, datetime.month, datetime.day, datetime.hour,
              datetime.minute, datetime.second, datetime.utc_hour_offset > 0 ? "+" : "-", datetime.utc_hour_offset,
              datetime.utc_minute_offset);
            return ret_string;
        }

        static string TransformSignatureStateToString(uint sig_state) 
        {
            if (0 == sig_state) return "Unknown";
            string state_str = "";
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateNoSignData)) > 0)
                state_str += "NoSignData";
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateUnsigned)) > 0) {
                if (state_str.Length>0) state_str += "|";
                state_str += "Unsigned";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateSigned)) > 0) {
                if (state_str.Length>0) state_str += "|";
                state_str += "Signed";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyValid)) > 0) {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerfiyValid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyInvalid)) > 0) {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyInvalid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyErrorData)) > 0) {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyErrorData";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyNoSupportWay)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyNoSupportWay";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyErrorByteRange)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyErrorByteRange";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyChange)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyChange";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyNoChange)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyNoChange";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIncredible)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIncredible";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueValid)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueValid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueUnknown)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueUnknown";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueRevoke)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueRevoke";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueExpire)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueExpire";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueUncheck)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueUncheck";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyIssueCurrent)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyIssueCurrent";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampNone)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyTimestampNone";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampDoc)) > 0)  {
                if (state_str.Length > 0) state_str += "|";
                state_str += "VerifyTimestampDoc";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampValid)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyTimestampValid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampInvalid)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyTimestampInvalid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampExpire)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyTimestampExpire";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampIssueUnknown)) > 0)  {
                if (state_str.Length>0) state_str += "|";
                state_str += "VerifyTimestampIssueUnknown";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampIssueValid)) > 0)  {
                if (state_str.Length > 0) state_str += "|";
                state_str += "VerifyTimestampIssueValid";
            }
            if ((sig_state & Convert.ToUInt32(Signature.States.e_StateVerifyTimestampTimeBefore)) > 0) {
                if (state_str.Length > 0) state_str += "|";
                state_str += "VerifyTimestampTimeBefore";
            }
            return state_str;
        }

        static void CheckSignatureInfo(PDFDoc pdf_doc) 
        {
            int sig_count = pdf_doc.GetSignatureCount();
            if (sig_count<1) {
                Console.WriteLine("No signature in current PDF file.");
                return;
            }
            for (int i = 0; i < sig_count; i++)
            {
                Console.WriteLine("Signature index: {0}", i);
                using (Signature signature = pdf_doc.GetSignature(i))
                {
                    if (signature.IsEmpty()) continue;
                    bool is_signed = signature.IsSigned();
                    Console.WriteLine("Signed?:{0}", is_signed ? "true" : "false");
                    uint sig_state = signature.GetState();
                    Console.WriteLine("State:{0}", TransformSignatureStateToString(sig_state));

                    using (Control control = signature.GetControl(0))
                    using (Widget widget_annot = control.GetWidget())
                    {
                        Console.WriteLine("Object number {0} of related widget annotation's dictionary", widget_annot.GetDict().GetObjNum());
                    }

                    String filter = signature.GetFilter();
                    Console.WriteLine("Filter:{0}", filter);
                    String sub_filter = signature.GetSubFilter();
                    Console.WriteLine("Sub-filter:{0}", sub_filter);
                    if (is_signed)
                    {
                        foxit.common.DateTime sign_time = signature.GetSignTime();
                        String time_str = DateTimeToString(sign_time);
                        Console.WriteLine("Sign Time:{0}", time_str);
                    }
                    string key_value;
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameSigner);
                    Console.WriteLine("Signer:{0}", key_value);
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameLocation);
                    Console.WriteLine("Location:{0}", key_value);
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameReason);
                    Console.WriteLine("Reason:{0}", key_value);
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameContactInfo);
                    Console.WriteLine("Contact Info:{0}", key_value);
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameDN);
                    Console.WriteLine("DN:{0}", key_value);
                    key_value = signature.GetKeyValue(Signature.KeyName.e_KeyNameText);
                    Console.WriteLine("Text:{0}", key_value);
                }
           }
       }

        static Signature AddSiganture(PDFPage pdf_page, string sub_filter) {
            float page_height = pdf_page.GetHeight();
            float page_width = pdf_page.GetWidth();
            RectF new_sig_rect = new RectF(0, (float)(page_height*0.9), (float)(page_width*0.4), page_height);
            // Add a new signature to page.
            Signature new_sig = pdf_page.AddSignature(new_sig_rect);
            if (new_sig.IsEmpty()) return null;
            // Set values for the new signature.
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameSigner, "Foxit PDF SDK");
            String new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameReason, new_value);
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameContactInfo, "support@foxitsoftware.com");
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameDN, "CN=CN,MAIL=MAIL@MAIL.COM");
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameLocation, "Fuzhou, China");
            new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
            new_sig.SetKeyValue(Signature.KeyName.e_KeyNameText, new_value);
            foxit.common.DateTime sign_time = GetLocalDateTime();
            new_sig.SetSignTime(sign_time);
            String image_file_path = input_path + "FoxitLogo.jpg";
            using (Image image = new Image(image_file_path))
            {
                new_sig.SetImage(image, 0);
                // Set appearance flags to decide which content would be used in appearance.
                int ap_flags = Convert.ToInt32(Signature.APFlags.e_APFlagLabel | Signature.APFlags.e_APFlagSigner |
                        Signature.APFlags.e_APFlagReason | Signature.APFlags.e_APFlagDN |
                        Signature.APFlags.e_APFlagLocation | Signature.APFlags.e_APFlagText |
                        Signature.APFlags.e_APFlagSigningTime | Signature.APFlags.e_APFlagBitmap);
                new_sig.SetAppearanceFlags(ap_flags);
            }

            return new_sig;
        }

        static SignatureCallbackImpl sig_callback = new SignatureCallbackImpl();
        static void AdobePPKLiteSignature(PDFDoc pdf_doc, bool use_default) {
            string filter = "Adobe.PPKLite";
            string sub_filter = "adbe.pkcs7.detached";

            if (!use_default) {
                sub_filter = "adbe.pkcs7.sha1";
                Library.RegisterSignatureCallback(filter, sub_filter, sig_callback);
            }

            Console.WriteLine("Use signature callback object for filter \"{0}\" and sub-filter \"{1}\"", filter, sub_filter);

            using (PDFPage pdf_page = pdf_doc.GetPage(0))
            {
                // Add a new signature to first page.
                using (Signature new_signature = AddSiganture(pdf_page, sub_filter))
                {
                    // Set filter and subfilter for the new signature.
                    new_signature.SetFilter(filter);
                    new_signature.SetSubFilter(sub_filter);
                    bool is_signed = new_signature.IsSigned();
                    uint sig_state = new_signature.GetState();
                    Console.WriteLine("[Before signing] Signed?:{0}\t State:{1}", is_signed,
                    TransformSignatureStateToString(sig_state));

                    // Sign the new signature.
                    String signed_pdf_path = output_directory + "signed_newsignature.pdf";
                    if (use_default)
                        signed_pdf_path = output_directory + "signed_newsignature_default_handler.pdf";

                    String cert_file_path = input_path + "foxit_all.pfx";
                    byte[] cert_file_password = Encoding.ASCII.GetBytes("123456");
                    // Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
                    // In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
                    new_signature.StartSign(cert_file_path, cert_file_password,
                                  Signature.DigestAlgorithm.e_DigestSHA1, signed_pdf_path, IntPtr.Zero, null);
                    Console.WriteLine("[Sign] Finished!");
                    is_signed = new_signature.IsSigned();
                    sig_state = new_signature.GetState();
                    Console.WriteLine("[After signing] Signed?:{0}\tState:{1}",
                      is_signed, TransformSignatureStateToString(sig_state));

                    // Open the signed document and verify the newly added signature (which is the last one).
                    Console.WriteLine("Signed PDF file: {0}", signed_pdf_path);
                    using (PDFDoc signed_pdf_doc = new PDFDoc(signed_pdf_path))
                    {
                        ErrorCode error_code = signed_pdf_doc.Load(null);
                        if (ErrorCode.e_ErrSuccess != error_code)
                        {
                            Console.WriteLine("Fail to open the signed PDF file.");
                            return;
                        }
                        // Get the last signature which is just added and signed.
                        int sig_count = signed_pdf_doc.GetSignatureCount();
                        using (Signature signed_signature = signed_pdf_doc.GetSignature(sig_count - 1))
                        {
                            // Verify the intergrity of signature.
                            signed_signature.StartVerify(IntPtr.Zero, null);
                            Console.WriteLine("[Verify] Finished!");
                            is_signed = signed_signature.IsSigned();
                            sig_state = signed_signature.GetState();
                            Console.WriteLine("[After verifying] Signed?:{0}\tState:{1}",
                               is_signed, TransformSignatureStateToString(sig_state));
                        }
                    }
                }
            }
        }

        static void Main(String[] args)
        {
            string input_file = input_path + "AboutFoxit.pdf";
            System.IO.Directory.CreateDirectory(output_directory);

            string sn = "Rew1vB0TqoMIxX444UcpScARWdhgJpsJfzmyMLR32a0+EgrCjp2NaQ==";
            string key = "8f3g1sFttW8NAgfSNv+BvaJWy4Pp8flcm7ncNDkdvCCO4JwUFbGLyZdujReMaiplbYJwwxam3lr7uHtQaEf0xTSu8j2ZBdrZ8FS4OQkEUjOI9UEGb3Ic0GqmlP9T9OnSItOYqoZZA/OnYg5EaVP+c/ha32nUquOk+5riEdhYgINAZDdgJkPc+YSWsrfixOIROf6t34j3eRcyFnOY0MS7tSXi1AEPE0VZdyu+5bfmBSGvLI+WR5lQ+oOQR5hRGwqf990WEdBelNO7dxhZELVhEZ+/L60PpDf5y9A8qmrY6PiEU8nhqIyLpks0BxeIsYyZ3Cr82jjfbItPGyEARsIVzluBSgVMD4oGjojz8T6wGDEXUbmZH/pra94XAs8wZ28mzbmIEppWnhBqX0c6Ov8iXCfFfUZr4KNuPxMEgk4VOYTMOd70GEjGnylivw18hbn7ZpkWh2Zql+uU2HejvOgn+WHvT0HF9NhK0Xb5vH8aFkgBP92PJx8obIbxBVeeExczxvsqWufuPdXS2sPNIgMYZ2TtvqVVsiUToeGB2FQo09fzZOSH5Vi18u/siyvC3FmjeMf4+OYWPuDPNCcrb21NgcHam7XI8AAoGLTGtLLWR+fxynbBBcg2d2ZPcZ5CMFIfOBHRWCkcA0sDT3cl9nsBppHNJze/jVxHy+lREeQEA/etSIgohTGAWW3ZlpibRXqMxlmVWEPifCubbWTzQ6U54mRMpW2UghH3gvCNFNgdday3Av7EtlIJOdUuiMq3zmmd5J4Jt4C82CKnVewA0DtZ4EEtwRG9IYuLrfpuZlnjBAtoeXRV1lqUZ6BcCe0E3m9jO28sGkALuIeJQ74XG7X8lMC7lMWWQYiYD7D6G9QT6X3qV4vXJwNKRKpYc/rI+amEawTSnDYAMEaYPwtZ0rb/7BL+atsZZaI+ncebdfVfjDJZbCZAc+JnkuNlUn2xrNRuObw8h/G0lm2pNOEJ10S8R4+yplo5B1QmC2dCDhaTaW67QJPqnJPKbVmjw7i6KGBi+CDP3JnAKlOX/YUu8uk56JfeQUuGcQg/KaBMGctnchH2n1i3+oGbibhurQj22+OO66Q6mijKoCRP/QJm5WTGcO4c0iVX0B8dIlai/uv/pGU8Wps9MxysH5ViVIj56LWKuNfy1FNO9+wx4iHYnUxfW0Iccq3YJYAlOBkMv8VZIJl9aTEEFJ626LJEw/UbEBdR9CdlwnylPf4RuNW/lcGYMgq3xNVpp/bzYKwZivvQOFgMdX1tv8D33SHvAm3zrRCU+v94BJXnBi9k25fnKsc705IMwv+I6bueXA+mDnagj1oTqsWXZ0WnPAYI3WUO7sBf7XUH230wfYXnTSVhujJxiEP/2oWqi2813gtQkKwz9N2p6yT8Vsh3+BaAwwDvtOZMJKUFcabTBSL6NoouzmzwItJ4mIboT6KXaef66rs8jCU=";
            // Initialize library
            ErrorCode error_code = Library.Initialize(sn, key);
            if (error_code != ErrorCode.e_ErrSuccess)
                Console.WriteLine("Library Initialize Error: {0}\n", error_code);

            try
            {
                for (int i = 0; i < 2; i++)
                {
                    using (PDFDoc pdf_doc = new PDFDoc(input_file))
                    {
                        pdf_doc.StartLoad(null, true, null);
                        // Check information of existed signature(s) in PDF file if there's any signature in the PDF file.
                        CheckSignatureInfo(pdf_doc);
                        // Add new signature, sign it and verify it with filter "Adobe.PPKLite" and different subfilter.
                        AdobePPKLiteSignature(pdf_doc, i > 0 ? false : true);
                        CheckSignatureInfo(pdf_doc);
                    }
                }
            }
            catch (PDFException e)
            {
                Console.WriteLine(e.Message);
            }
            Library.Release();
        }
    }
}
