Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 保护数据。保护间歇性故障_C#_.net_Security_Encoding_Cryptography - Fatal编程技术网

C# 保护数据。保护间歇性故障

C# 保护数据。保护间歇性故障,c#,.net,security,encoding,cryptography,C#,.net,Security,Encoding,Cryptography,我正在写一个密码加密程序。我已经编写了下面的应用程序来说明我的问题。大约20%的情况下,此代码按预期工作。其余时间,解密抛出加密异常-“数据无效” 我相信问题出在加密部分,因为解密部分每次都是一样的。也就是说,如果加密例程产生一个解密例程可以解密的值,那么它总是可以解密它。但是,如果加密例程产生的值阻塞了解密例程,那么它总是阻塞。因此,解密例程是一致的;加密例程不可用 我怀疑我使用的Unicode编码是不正确的,但我也尝试过其他方法,得到了相同的结果 我做错了什么 using System; u

我正在写一个密码加密程序。我已经编写了下面的应用程序来说明我的问题。大约20%的情况下,此代码按预期工作。其余时间,解密抛出加密异常-“数据无效”

我相信问题出在加密部分,因为解密部分每次都是一样的。也就是说,如果加密例程产生一个解密例程可以解密的值,那么它总是可以解密它。但是,如果加密例程产生的值阻塞了解密例程,那么它总是阻塞。因此,解密例程是一致的;加密例程不可用

我怀疑我使用的Unicode编码是不正确的,但我也尝试过其他方法,得到了相同的结果

我做错了什么

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace DataProtectionTest
{
    public partial class Form1 : Form
    {
        private static readonly byte[] entropy = { 1, 2, 3, 4, 1, 2, 3, 4 };
        private string password;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnEncryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pw = Encoding.Unicode.GetBytes(textBox1.Text);
            Byte[] encryptedPw = ProtectedData.Protect(pw, entropy, DataProtectionScope.LocalMachine);
            password = Encoding.Unicode.GetString(encryptedPw);     
        }

        private void btnDecryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pwBytes = Encoding.Unicode.GetBytes(password);
            try
            {
                Byte[] decryptedPw = ProtectedData.Unprotect(pwBytes, entropy, DataProtectionScope.LocalMachine);
                string pw = Encoding.Unicode.GetString(decryptedPw);
                textBox2.Text = pw;
            }
            catch (CryptographicException ce)
            {
                textBox2.Text = ce.Message;
            }
        }
    }
}

我强烈怀疑是对Encoding.Unicode.GetString的调用造成了问题。您需要确保传递给Unprotect调用的数据与Protect调用返回的数据完全相同。如果将二进制数据编码为Unicode文本作为过渡步骤,则不能保证这一点。无论如何,为什么需要此步骤?为什么不存储字节[]?

最好的解决方案是

对于这种情况,还可以使用拉丁语-1 aka ISO-8859-1 aka代码页28591,因为它映射0-255范围内的值。以下是可互换的:

Encoding.GetEncoding(28591)
Encoding.GetEncoding("Latin1")
Encoding.GetEncoding("iso-8859-1")
使用这种编码,您将始终能够在不丢失的情况下转换byte[]->string->byte[]


有关此编码的使用示例,请参见。

根据一位同事的建议,我选择了Convert.ToBase64String。效果很好。更正了下面的程序

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace DataProtectionTest
{
    public partial class Form1 : Form
    {
        private static readonly byte[] entropy = { 1, 2, 3, 4, 1, 2, 3, 4 };
        private string password;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnEncryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pw = Encoding.Unicode.GetBytes(textBox1.Text);
            Byte[] encryptedPw = ProtectedData.Protect(pw, entropy, DataProtectionScope.LocalMachine);
            //password = Encoding.Unicode.GetString(encryptedPw);       
            password = Convert.ToBase64String(encryptedPw);
        }

        private void btnDecryptIt_Click(object sender, EventArgs e)
        {
            //Byte[] pwBytes = Encoding.Unicode.GetBytes(password);
            Byte[] pwBytes = Convert.FromBase64String(password);
            try
            {
                Byte[] decryptedPw = ProtectedData.Unprotect(pwBytes, entropy, DataProtectionScope.LocalMachine);
                string pw = Encoding.Unicode.GetString(decryptedPw);
                textBox2.Text = pw;
            }
            catch (CryptographicException ce)
            {
                textBox2.Text = ce.Message;
            }
        }
    }
}

问题是转换为unicode和加密方法ENCONDING.unicode.GetString的结尾只有在您提供的字节形成有效的UTF-16字符串时才起作用


我怀疑有时ProtectedData.Protect的结果不是有效的UTF-16字符串-因此Encoding.Unicode.GetString会从返回的字符串中删除没有意义的字节,从而导致无法转换回加密数据的字符串。

您不应为密文。您将遇到间歇性错误。您应该使用Base64编码和
系统.Convert
类方法

  • 要从加密的
    字节[]
    获取加密的
    字符串
    ,您应该使用:

    Convert.ToBase64String(byte[] bytes)
    
    Convert.FromBase64String(string data)
    
  • 要从要加密的
    字符串中获取原始
    字节[]
    ,应使用:

    Convert.ToBase64String(byte[] bytes)
    
    Convert.FromBase64String(string data)
    

  • 有关更多信息,请参阅本课程的帮助:

    public static class StringEncryptor
    {
        private static readonly byte[] key = { 0x45, 0x4E, 0x3A, 0x8C, 0x89, 0x70, 0x37, 0x99, 0x58, 0x31, 0x24, 0x98, 0x3A, 0x87, 0x9B, 0x34 };
    
        public static string EncryptString(this string sourceString)
        {
            if (string.IsNullOrEmpty(sourceString))
            {
                return string.Empty;
            }
    
            var base64String = Base64Encode(sourceString);
            var protectedBytes = ProtectedData.Protect(Convert.FromBase64String(base64String), key, DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(protectedBytes);
        }
    
        public static string DecryptString(this string sourceString)
        {
            if (string.IsNullOrEmpty(sourceString))
            {
                return string.Empty;
            }
    
            var unprotectedBytes = ProtectedData.Unprotect(Convert.FromBase64String(sourceString), key, DataProtectionScope.CurrentUser);
            var base64String = Convert.ToBase64String(unprotectedBytes);
            return Base64Decode(base64String);
        }
    
        private static string Base64Encode(string plainText)
        {
            var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            return Convert.ToBase64String(plainTextBytes);
        }
    
        private static string Base64Decode(string base64EncodedData)
        {
            var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
            return Encoding.UTF8.GetString(base64EncodedBytes);
        }
    }
    

    我正在转换回字符串,因为我需要将其作为varchar存储在数据库中。此代码中仍有一个错误…请参阅下面的答案。将其转换为Base64字符串和从Base64字符串转换为Base64字符串的操作解决了我的问题。之前我在转换unicode字符串。真的很有用。谢谢