似乎无法解决这个问题......我正在使用DESCryptoServiceProvider进行快速的双向加密(与安全无关,安全性不是此问题的目的)。
无论如何它很奇怪,因为进入然后返回的字符串只能正确解密字符串的一半。我似乎无法注意到这个错误,所以也许有人会对此有所了解......
我将两个字符串与冒号组合作为分隔符,因此' abc12345:xyz56789'是输入。然后在输出中注意只有字符串的第一部分被搞砸了,而不是第二部分。我希望如果我完全错了,那么整个事情都不会正确解密。
以下是所有代码:
class Program
{
static void Main(string[] args)
{
var userId = "abc12345";
var appId = "xyz56789";
Console.WriteLine($"UserId: {userId}, AppId: {appId}");
var code = QuickEncode(userId, appId);
Console.WriteLine(code);
var result = QuickDecode(code);
var uId = result.Item1;
var aId = result.Item2;
Console.WriteLine($"UserId: {uId}, AppId: {aId}");
Console.ReadKey();
}
private static string QuickEncode(string userId, string appId)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
var desKey = StringToByteArray("437459133faf42cb");
des.Key = desKey;
ICryptoTransform encryptor = des.CreateEncryptor();
var encryptMe = $"{userId}:{appId}";
Console.WriteLine($"Input String: {encryptMe}");
byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(encryptMe);
byte[] enc = encryptor.TransformFinalBlock(stringBytes, 0, stringBytes.Length);
var encryptedBytesString = Convert.ToBase64String(enc);
return encryptedBytesString;
}
private static Tuple<string, string> QuickDecode(string code)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
var desKey = StringToByteArray("437459133faf42cb");
des.Key = desKey;
ICryptoTransform decryptor = des.CreateDecryptor();
var codeBytes = Convert.FromBase64String(code);
byte[] originalAgain = decryptor.TransformFinalBlock(codeBytes, 0, codeBytes.Length);
var decryptMe = System.Text.Encoding.UTF8.GetString(originalAgain);
Console.WriteLine($"Output String: {decryptMe}");
var ids = decryptMe.Split(':');
return new Tuple<string, string>(ids[0], ids[1]);
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
}
答案 0 :(得分:3)
您必须将initialization vector(IV)设置为相同的加密值和解密值。因为为每个新的DESCryptoServiceProvider实例自动生成了新的IV,所以您的IV不同并且解密不成功。
正确解密一半邮件的原因是使用CBC mode(默认模式),这有一个非常讨厌的属性,只有第一块加密邮件实际上取决于IV的值,所以潜在的攻击者可以解码除第一个块之外的所有消息,而不知道正确的IV(当然,仍然需要正确的密钥)。因此不建议使用此模式。有关详细信息,请参阅Block cipher mode of operation。
因此解决方案很容易 - 存储在用于加密的IV处,并使用相同的IV进行解密。如果可能,也使用另一个密码模式。像这样的事情:
using System;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main(string[] args)
{
var userId = "abc12345";
var appId = "xyz56789";
Console.WriteLine($"UserId: {userId}, AppId: {appId}");
byte[] IV;
var code = QuickEncode(userId, appId, out IV);
Console.WriteLine(code);
var result = QuickDecode(code, IV);
var uId = result.Item1;
var aId = result.Item2;
Console.WriteLine($"UserId: {uId}, AppId: {aId}");
Console.ReadKey();
}
private static string QuickEncode(string userId, string appId, out byte[] IV)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
var desKey = StringToByteArray("437459133faf42cb");
des.Key = desKey;
des.GenerateIV();
IV = des.IV;
ICryptoTransform encryptor = des.CreateEncryptor();
var encryptMe = $"{userId}:{appId}";
Console.WriteLine($"Input String: {encryptMe}");
byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(encryptMe);
byte[] enc = encryptor.TransformFinalBlock(stringBytes, 0, stringBytes.Length);
var encryptedBytesString = Convert.ToBase64String(enc);
return encryptedBytesString;
}
private static Tuple<string, string> QuickDecode(string code, byte[] IV)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
var desKey = StringToByteArray("437459133faf42cb");
des.Key = desKey;
des.IV = IV;
ICryptoTransform decryptor = des.CreateDecryptor();
var codeBytes = Convert.FromBase64String(code);
byte[] originalAgain = decryptor.TransformFinalBlock(codeBytes, 0, codeBytes.Length);
var decryptMe = System.Text.Encoding.UTF8.GetString(originalAgain);
Console.WriteLine($"Output String: {decryptMe}");
var ids = decryptMe.Split(':');
return new Tuple<string, string>(ids[0], ids[1]);
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
}