Ejemplo n.º 1
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 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);
        }