1

上下文:

我目前正在为 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

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

4

1 回答 1

2

数字签名和数字化签名的区别

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

  1. 真实的(即当信上写着“你的妈妈”时,实际上是你妈妈写的)
  2. 原创(即在你妈妈写信后没有人修改你妈妈的信的内容)

现在,模拟现实生活中实际的手写签名是数字签名世界中的私钥。这个数字签名的定义就是这个美国政府的事情所涉及的。

您所说的第二件事是将手写签名数字化。数字化的手写签名不是数字签名

无论如何,混合这些完全不同的概念有很多理由。例如,数字签名算法可用于确保以数字方式记录的手写签名是真实的和原始的。这就是您提到的教程的内容。

话虽如此,主要问题是:您的要求是什么?尤其是在安全方面。

解法原理

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

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

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

创建一个随机的公钥和私钥对(APub、APriv)。

使用数字签名算法对数据(加密或原始)进行签名

销毁密钥APriv

将数据与密钥APub一起保存。

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

当然不是这样

上面的解决方案非常不安全。最糟糕的是,尽管记录一旦存储在数据库中就无法更改,但可以替换它,而没有人会注意到。为避免这种情况,您需要一个证书,或多或少与一对私钥和公钥相同(我希望我不会因此而被宰),这是唯一有权签署数据的实例。然后系统的安全性就会崩溃,以确保您的证书不会落入坏人之手。您可以考虑一个请求在中央服务器上签署数据的 Web 服务。您需要再次使用加密和数字签名来保护通信通道。每个设备都有自己的证书。这样您就可以跟踪服务器上的所有内容:哪个设备在什么时间使用什么证书请求了什么签名。这可能会接近法律当局接受的系统(不要把我钉在这个上面)。

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

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

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

结论

没有一个系统是完全安全的,最重要的是要明确要求。否则它很快就会变得昂贵。滥用总是有很多选择,请确保您的证书不能被不应被允许的人访问。

于 2013-10-14T10:36:35.253 回答