我如何确保我在wpf上收集的签名在法庭上是合法的

时间:2013-10-14 09:18:43

标签: c# wpf certificate digital-signature

上下文:

我目前正在为Windows平板电脑创建一个WPF应用程序。这个应用程序应该取代纸质工作。目前的纸质表格是一张纸,一名军人写下他在工作上花费的时间,他使用的材料以及他在那里时所做的事情。 当工作完成后,他将此表格显示给客户,客户签字。该公司希望将其数字化,并且我一直在编写用于捕获签名的用户控件。我以本教程为例http://msdn.microsoft.com/en-us/library/aa480678.aspx。虽然它是在vb中我在C#中使用了相同的加密机制 美国政府(虽然我是来自荷兰的,但我认为我会用英语引用一些东西,所以我认为以下是关于数字签名的说法: http://usgovinfo.about.com/library/bills/bldigitalsigs.htm 存储客户签名的所有数据存储在序列化数据类中(使用MVVM模式,因此很容易将所有数据放在一起)

我已经完成了一些关于数字签名的研究但是我读的越多,我就越害怕我不能成为我自己。

问题: 如何获得有效证书以确保签名有效。

这实际上是第二个问题.. 如何使用该签名加密我的数据,因此毫无疑问该数据是为

签名的

部分代码: 加密方法:

public void Encrypt(InkSecureSignatureData signatureData)
        {

            try
            {
                // Block sizes and buffer for stream operations.
                const int SMALLEST = 86;
                const int BLOCK = 128;
                byte[] Buffer = new byte[SMALLEST];
                // Variables for Ink data.
                StrokeCollection CopyOfSourceInk = new StrokeCollection();
                StrokeCollection WashedInk = new StrokeCollection();
                // Serialized signature objects.
                System.IO.MemoryStream SourceStream = new System.IO.MemoryStream();
                System.IO.MemoryStream EncryptedStream = new System.IO.MemoryStream();

                signatureData.BiometricEncryptionSubmittedOn = DateTime.Now;

                // Store the machine name in the HardwareInfo property.
                signatureData.HardwareInfo = Environment.MachineName;

                // Create a working copy of the SignatureData's ink.
                using (MemoryStream ms = new MemoryStream(signatureData.InkSecureSignature))
                {
                    CopyOfSourceInk = new System.Windows.Ink.StrokeCollection(ms);
                    ms.Close();
                }
                //CopyOfSourceInk.Load(signatureData.InkSecureSignature);

                // Wash each Stroke by using GetFlattenedBezierPoints
                // to remove all pressure information.
                foreach (Stroke Stroke in CopyOfSourceInk)
                {
                    //WashedInk.CreateStroke(Stroke.GetFlattenedBezierPoints(500));
                    WashedInk.Add(new Stroke(Stroke.GetBezierStylusPoints()));
                }

                //signatureData.InkWashedSignature = WashedInk.Save(PersistenceFormat.InkSerializedFormat, CompressionMode.Default);
                byte[] signature;
                using (MemoryStream ms = new MemoryStream())
                {
                    WashedInk.Save(ms);
                    signature = ms.ToArray();
                }
                signatureData.InkWashedSignature = signature;

                // Create a key and establish RSAKeyInfo.
                byte[] PublicKey = {//some huge as byte array which i'm not gonna add here}
                byte[] Exponent = {
                1,
                0,
                1
            };
                RSAParameters RSAKeyInfo = new RSAParameters();
                RSAKeyInfo.Modulus = PublicKey;
                RSAKeyInfo.Exponent = Exponent;
                System.Security.Cryptography.RSACryptoServiceProvider RSA = new System.Security.Cryptography.RSACryptoServiceProvider();
                RSA.ImportParameters(RSAKeyInfo);

                // Serialize the signature.
                System.Xml.Serialization.XmlSerializer Serializer = new System.Xml.Serialization.XmlSerializer(typeof(InkSecureSignatureData));
                Serializer.Serialize(SourceStream, signatureData);

                // Cycle through the in-memory stream and encrypt it.
                SourceStream.Position = 0;

                while ((SourceStream.Read(Buffer, 0, SMALLEST) >= SMALLEST))
                {
                    if ((SourceStream.Position < SourceStream.Length))
                    {
                        EncryptedStream.Write(RSA.Encrypt(Buffer, true), 0, BLOCK);
                    }
                }

                // Handle the remaining bytes in the stream.
                long Amount = SourceStream.Length % SMALLEST;
                byte[] Remaining = new byte[Amount];
                Array.Copy(Buffer, Remaining, Amount);
                EncryptedStream.Write(RSA.Encrypt(Remaining, true), 0, BLOCK);

                // Place the encrypted data in the InkSecureSignatureData object.
                signatureData.EncryptedBiometricData = EncryptedStream.ToArray();
                signatureData.BiometricEncryptionCompletedOn = DateTime.Now;

                // Blank out the original signature to prevent expropriation.
                signatureData.InkSecureSignature = null;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

我收集签名的部分类:

public partial class DrawSignatureScreen : Window
    {
        // Locks the signature.
        private bool signatureReadOnly;
        // The caption for the signer's name.
        private string signersNameCaptionValue = "Signer's Name: ";

        /// <summary>
        /// Occurs when the signature has been fully signed.
        /// </summary>
        /// <param name="sender">The source InkSecureSignature object for this event.</param>
        /// <param name="e">The EventArgs object that contains the event data.</param>
        public event SignedEventHandler Signed;
        public delegate void SignedEventHandler(object sender, EventArgs e);

        public DrawSignatureScreen()
        {
            InitializeComponent();
            signatureInkCanvas.StrokeCollected += signatureInkOverlay_Stroke;
        }

        /// <summary>
        /// Gets or sets the override to the default "Signer's Name:" label caption.
        /// </summary>
        public string SignersNameCaption
        {
            get
            {
                return signersNameCaptionValue;
            }
            set
            {
                signersNameCaptionValue = value;
                signersNameLabel.Content = signersNameCaptionValue;
            }
        }


        /// <summary>
        /// Gets or sets whether the signature has been completed.
        /// </summary>
        /// <remarks>
        /// After the signature is accepted, this property is true, and
        /// it cannot be changed back to false. This would enable the
        /// modification of the signature after acceptance.
        /// </remarks>
        public bool SignatureComplete
        {
            get
            {
                return signatureReadOnly;
            }
            set
            {
                // If the signature is already accepted, then exit.
                if ((signatureReadOnly == true) | (value == signatureReadOnly))
                {
                    return;
                }
                // Because we got this far, Value is True, 
                // so lock all controls and disable Ink collection.
                acceptButton.Visibility = Visibility.Hidden;
                if ((signatureInkCanvas != null))
                {
                    signatureInkCanvas.IsEnabled = false;
                }
                signersNameTextBox.Visibility = Visibility.Hidden;
                // Set the signer's name label control to the current caption for 
                // the signer's name plus the actual signer's name.
                signersNameLabel.Content = signersNameCaptionValue + (this.DataContext as InkSecureSignatureData).SignersName;

                // Set the read-only property value.
                signatureReadOnly = value;
                cancelButton.Content = "OK";
            }
        }
        //
        // SetDefaultDrawingAttributes
        //
        // Set the default drawing attributes for ink collection.
        //
        // Parameters:
        //  color - The desired ink color.
        //

        private void SetDefaultDrawingAttributes(System.Drawing.Color color)
        {
            var _with1 = signatureInkCanvas.DefaultDrawingAttributes;
            // Color.
            _with1.Color = System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B);
            // Smooth.
            //_with1.AntiAliased = true;
            _with1.FitToCurve = true;
            // Set to not round (modify) the Stroke.
            //_with1.PenTip = PenTip.Ball;
            _with1.StylusTip = StylusTip.Ellipse;
            // Ball Point.
            _with1.Width = 2;
            // Size.
        }

        // signatureInkOverlay_Stroke
        //
        // On the first Stroke, set the timestamp and button state.
        //
        // Parameters:
        //  sender - The source InkOverlay object for this event.
        //  e - The InkCollectorStrokeEventArgs object that contains the event data.
        // 

        private void signatureInkOverlay_Stroke(object sender, InkCanvasStrokeCollectedEventArgs e)
        {
            // First, check to ensure that this is the first Stroke, otherwise exit.
            if (signatureInkCanvas.Strokes.Count > 1)
            {
                return;
            }
            // Set the Acquired Signature Start On to Now.
            (this.DataContext as InkSecureSignatureData).AcquiredSignatureStartOn = DateTime.Now;

            // Enable the clear button.
            clearButton.IsEnabled = true;

            // Call ValidateData to see if all of the required
            // criteria has been met to "accept" the signature.
            ValidateData();

        }

        //
        // signersNameTextBox_TextChanged
        //
        // Occurs when the Text property value changes.
        //
        // Parameters:
        //  sender - The source TextBox object for this event.
        //  e - The EventArgs object that contains the event data.
        // 

        private void signersNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Assign the signer's name from the text box to the underlying data object.
            (this.DataContext as InkSecureSignatureData).SignersName = signersNameTextBox.Text;
            ValidateData();
        }

        //
        // clearButton_Click
        //
        // Occurs when the Button is clicked to clear the signature in process.
        //
        // Parameters:
        //  sender - The source Button object for this event.
        //  e - The EventArgs object that contains the event data.
        // 
        private void clearButton_Click(object sender, RoutedEventArgs e)
        {
            SignatureComplete = false;
            signatureReadOnly = false;
            // Delete the Strokes collection.
            signatureInkCanvas.Strokes.Clear();
            // Disable the clear button.
            clearButton.IsEnabled = false;
            signersNameTextBox.Text = "";
            signersNameLabel.Content = "Signer's name:";
            signatureInkCanvas.IsEnabled = true;
            SetDefaultDrawingAttributes(Color.Black);
            // Revalidate the data.
            ValidateData();
        }

        /// <summary>
        /// Prints the signature.
        /// </summary>
        /// <param name="graphics">The Graphics context to print to.</param>
        /// <param name="topLeftPoint">The top left corner of the print area.</param>

        public void Print(Graphics graphics, System.Drawing.Point topLeftPoint)
        {
            // Starting locations.
            int Indentation = 5;
            int BottomLineY = 17;
            int VerticalLocation = (int)topLeftPoint.Y;

            // Specify a bordered print area slightly smaller than the control.
            Rectangle ThisRect = new Rectangle(topLeftPoint.X, topLeftPoint.Y, 800, 281);
            Color BorderColor = Color.FromArgb(255, 0, 45, 150);
            Microsoft.Ink.Renderer Renderer = new Microsoft.Ink.Renderer();

            var _with2 = graphics;
            _with2.FillRectangle(Brushes.White, ThisRect);
            _with2.DrawRectangle(new Pen(BorderColor), ThisRect);

            // Draw the bottom line.
            _with2.DrawLine(Pens.Black, Indentation, ThisRect.Height - BottomLineY, ThisRect.Width - (2 * Indentation), ThisRect.Height - BottomLineY);

            if (SignatureComplete == false)
            {
                // Draw a blank signature line.
                _with2.DrawString("Signed: ", new Font(new System.Drawing.FontFamily("arial"),10f), new SolidBrush(Color.Black), ThisRect.Left + Indentation, ThisRect.Height - BottomLineY + 1);
            }
            else
            {
                // Draw header text and washed Ink.
                _with2.DrawString("RSA Encrypted Digital Biometric Signature", new Font(new System.Drawing.FontFamily("arial"), 10f), new SolidBrush(Color.Blue), ThisRect.Left + 3, VerticalLocation + 3);

                graphics.SmoothingMode = SmoothingMode.AntiAlias;
                graphics.CompositingMode = CompositingMode.SourceOver;
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;

                StrokeCollection sc = signatureInkCanvas.Strokes;
                byte[] inkData = null;
                using (MemoryStream inkMemStream = new MemoryStream())
                {
                    sc.Save(inkMemStream);
                    inkData = inkMemStream.ToArray();
                }
                Ink ink = new Ink();
                ink.Load(inkData);

                Microsoft.Ink.DrawingAttributes da = new Microsoft.Ink.DrawingAttributes(Color.Black);
                da.AntiAliased = true;
                da.FitToCurve = false;
                da.RasterOperation = RasterOperation.Black;
                foreach (Microsoft.Ink.Stroke Stroke in ink.Strokes)
                {
                    Renderer.Draw(graphics, Stroke, da);
                }

                _with2.DrawString("Signed By: " + (this.DataContext as InkSecureSignatureData).SignersName.ToString() + " on " + (this.DataContext as InkSecureSignatureData).SignerAcceptedOn.ToString(), new Font(new System.Drawing.FontFamily("arial"), 10f), new SolidBrush(Color.Blue), ThisRect.Left + Indentation, ThisRect.Height - BottomLineY + 1);
            }
        }

        //public void Reset()
        //{
        //    (this.DataContext as Collection).Signatures = "<InkSecureSignatureData/>";

        //}

        //
        // acceptButton_Click
        //
        // Occurs when the Button is clicked to lock the signature.
        //
        // Parameters:
        //  sender - The source Button object for this event.
        //  e - The EventArgs object that contains the event data.
        // 

        private void acceptButton_Click(System.Object sender, System.EventArgs e)
        {
            var _with3 = (this.DataContext as InkSecureSignatureData);
            // Save the serialized Ink to the SignatureData.InkSecureSignature property
            // for encryption by the Biometric Encryption Provider for Ink.

            MemoryStream ms = new MemoryStream();
            signatureInkCanvas.Strokes.Save(ms);
            _with3.InkSecureSignature = ms.ToArray();

            _with3.SignerAcceptedOn = DateTime.Now;

            BiometricEncryptionProviderForInk BiometricEncryptionProvider = new BiometricEncryptionProviderForInk();

            try
            {
                // Wash and encrypt the signature data.
                BiometricEncryptionProvider.Encrypt((this.DataContext as InkSecureSignatureData));

                // Stop collecting Ink and show the washed Ink.
                this.SignatureComplete = true;
                //CreateNewInkCanvas();
                SetDefaultDrawingAttributes(Color.Black);

                ms = new MemoryStream((this.DataContext as InkSecureSignatureData).InkWashedSignature);
                signatureInkCanvas.Strokes = new StrokeCollection(ms);

                System.Drawing.Bitmap signatureBitmap = new System.Drawing.Bitmap(803, 284, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

                //Create a graphics context from that bitmap image.
                Graphics graphics = System.Drawing.Graphics.FromImage(signatureBitmap);

                // Print the InkSecureSignature to the bitmap.
                Print(graphics, new System.Drawing.Point(1, 1));

                ImageConverter converter = new ImageConverter();
                _with3.Signature = (byte[])converter.ConvertTo(signatureBitmap, typeof(byte[]));

                // Clean up.
                graphics.Dispose();

                //TODO remove when done with testing
                signatureBitmap.Save("test.Jpeg", ImageFormat.Jpeg);

                // Tell the calling form that the control is done processing.
                if (Signed != null)
                {
                    Signed(this, new EventArgs());
                }
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        //
        // ValidateData
        //
        // Sets the Accept button's state depending on the presence of required inputs.
        //

        private void ValidateData()
        {
            acceptButton.IsEnabled = (signatureInkCanvas.Strokes.Count > 0) && (signersNameTextBox.Text.Length > 0);
            if (!acceptButton.IsEnabled)
            {
                acceptButton.Visibility = Visibility.Visible;
                signersNameTextBox.Visibility = Visibility.Visible;
            }
        }
    }

InkSecureSignatureData中的字段用于存储从签名中收集的所有(加密)数据:

private System.DateTime mAcquiredSignatureStartOn;
private System.DateTime mBiometricEncryptionSubmittedOn;
private System.DateTime mBiometricEncryptionCompletedOn;
private byte[] mEncryptedBiometricData;
private string mHardwareInfo;
private byte[] mInkWashedSignature;
private byte[] mInkSignature;
private System.DateTime mSignerAcceptedOn;
private byte[] signatureBitmap;
private string mSignersName;

最后我有一个名为'Collection'的类,它存储了所有输入的数据,它还存储了包含类InkSecureSignatureData的类。

我希望我提供了足够的信息,如果有什么不清楚,请询问,我会尽力回答。

1 个答案:

答案 0 :(得分:2)

数字签名与数字化签名之间的差异

你在这里混淆了一些东西:数字签名是一种非对称的加密算法,与写下你的名字无关,既不是老式的纸笔式也不是任何一种。数字设备。它被称为数字签名,因为它可以用于相同的目的:确保数据

  1. 真实(即当信中写着'你的,妈妈'时,它就是 实际上你的妈妈写了它)
  2. 原始(即在您妈妈写完之后没有人修改过您母亲的信件内容)
  3. 现在,模拟现实生活中的实际手写签名是数字签名世界中的私钥数字签名的定义就是美国政府所涉及的内容。

    你要谈的第二件事就是手写签名的数字化。数字化手写签名不是数字签名

    无论如何,有很多理由将这些完全不同的概念混合在一起。例如,数字签名算法可用于确保数字记录的手写签名是可信原始。这就是你提到的教程。

    话虽如此,主要问题是:您有什么要求?特别是关于安全性。

    解决方案原则

    我将从这里开始:主要目标是将数字化签名绑定到数据集,其方式是数据集之后无法更改。作为一个概念,以下算法将实现这一目标:

    鉴于数据,以及任何格式的数字化签名(InkSecureSignature在这里都很好,重要的是签名需要以禁止滥用的格式存在。这意味着,数据的质量需要“足够糟糕”):

    定义一个保存数据的类和签名序列化它。

    创建随机公钥和私钥对(APub,APriv)。

    使用数字签名算法对数据进行签名(enrypted或original)

    销毁密钥 APriv

    使用密钥 APub 保存数据。

    现在,使用密钥 APub ,您将能够检查数据和数字化签名是否已经打包在一起并且自那以后没有改变。

    那不是它,当然

    上述解决方案非常不安全。最糟糕的是,虽然记录一旦存储在数据库中,就无法改变,它可以被替换,没有人会注意到。为了避免这种情况,您需要一个证书,或多或少与一对私钥和公钥相同(我希望我不会因此而被屠杀)这是唯一一个签署数据的权利。然后,系统的安全性会降低,以确保您的证书不会落入错误的人手中。您可以考虑请求在中央服务器上签名数据的Web服务。您需要再次使用加密和数字签名来保护通信通道。每个设备都有自己的证书。这样你就可以跟踪服务器上的所有内容:哪个设备在什么时候使用什么证书请求了什么签名。这可能接近一个法律机构会接受的制度(不要指责我)。

    如果您的软件可能被黑客入侵

    其次,可以使用已存在于数据库中的数字化签名来签署新数据。几乎没有任何安全的解决方案,只要您必须考虑某人在代码级别操作您的软件。或者,您可以确保没有人拥有数据库中数据的访问权限。即您可以对所有内容进行加密,并确保只有CEO拥有加密数据的证书;)。

    如果您无法确定您的软件不会被黑客攻击,则只有一种方法可以确保系统安全:没有数字化签名,只有数字签名。每个客户都有自己的数字证书并对其负责。签名需要使用此证书以数字方式执行。当然,滥用的可能性很大,但您已将风险委托给客户。

    <强>结论

    任何系统都不是完全安全的,最重要的是要满足要求。否则它会很快变得昂贵。滥用的选项总是很多,请确保不允许的人访问您的证书。