什么是使用AES加密URL链接以使用VB.NET 2005将用户名传递到ASP.NET中的另一个网站的好链接或文章?仅供参考:接收网站将有权访问私钥以进行解密.
不要这样做!编写自己的加密系统很容易导致出错.最好使用现有系统,如果没有,请让知道密码学的人去做.如果您必须自己动手,请阅读Practical Cryptography.
请记住:"我们已经拥有足够快速,不安全的系统." (布鲁斯施奈尔) - 做正确的事情并担心以后的表现.
也就是说,如果你坚持使用AES来推销自己的,那么这里有一些指示.
AES是分组密码.给定一个密钥和一个明文块,它将其转换为特定的密文.这样做的问题是,每次使用相同的密钥生成相同的密钥时,相同的数据块.所以假设你发送这样的数据:
用户=加密(用户名)&角色=加密(的UserRole)
它们是两个独立的块,UserRoles加密每次都有相同的密文,无论名称如何.我需要的只是管理员的密文,我可以使用我的密码用户名将其删除.哎呀.
因此,存在密码操作模式.主要思想是你将获取一个块的密文,并将其XOR转换为下一个块的密文.这样我们就会进行加密(UserRoles,用户名),并且用户名密文会受到UserRoles的影响.
问题是第一个块仍然容易受到攻击 - 只要看到某个人的密文,我就会知道他们的角色.输入初始化向量.IV"启动"密码并确保其具有随机数据以加密流的其余部分.所以现在UserRoles密文具有随机IV异或的密文.问题解决了.
因此,请确保为每条消息生成随机IV.IV不敏感,可以用密文发送明文.使用足够大的IV - 在许多情况下,块的大小应该没问题.
AES不提供完整性功能.任何人都可以修改您的密文,解密仍然有效.它一般不太可能是有效数据,但可能很难知道有效数据是什么.例如,如果您正在传输加密的GUID,则很容易修改某些位并生成完全不同的位.这可能会导致应用程序错误等.
修复是在明文上运行哈希算法(使用SHA256或SHA512),并将其包含在您传输的数据中.因此,如果我的消息是(UserName,Roles),您将发送(UserName,Roles,Hash(UserName,Roles)).现在,如果有人通过翻转来篡改密文,则哈希将不再计算,您可以拒绝该消息.
如果需要从密码生成密钥,请使用内置类:System.Security.Cryptography.PasswordDeriveBytes.这提供了salting和迭代,这可以提高派生密钥的强度,并减少密钥泄露时发现密码的机会.
编辑:很抱歉没有提到这个:P.您还需要确保拥有防重播系统.如果您只是加密邮件并传递它,那么获取邮件的任何人都可以重新发送邮件.为避免这种情况,您应该为邮件添加时间戳.如果时间戳与特定阈值不同,请拒绝该消息.您可能还希望包含一次性ID(可能是IV)并拒绝来自使用相同ID的其他IP的时间有效消息.
在包含时序信息时,确保进行哈希验证非常重要.否则,如果您没有检测到这种强力尝试,有人可能会篡改一些密文并可能生成有效的时间戳.
由于显然正确地使用IV对某些人来说是有争议的,这里有一些代码可以生成随机IV并将它们添加到您的输出中.它还将执行身份验证步骤,确保未修改加密数据.
using System; using System.Security.Cryptography; using System.Text; class AesDemo { const int HASH_SIZE = 32; //SHA256 ///Performs encryption with random IV (prepended to output), and includes hash of plaintext for verification. public static byte[] Encrypt(string password, byte[] passwordSalt, byte[] plainText) { // Construct message with hash var msg = new byte[HASH_SIZE + plainText.Length]; var hash = computeHash(plainText, 0, plainText.Length); Buffer.BlockCopy(hash, 0, msg, 0, HASH_SIZE); Buffer.BlockCopy(plainText, 0, msg, HASH_SIZE, plainText.Length); // Encrypt using (var aes = createAes(password, passwordSalt)) { aes.GenerateIV(); using (var enc = aes.CreateEncryptor()) { var encBytes = enc.TransformFinalBlock(msg, 0, msg.Length); // Prepend IV to result var res = new byte[aes.IV.Length + encBytes.Length]; Buffer.BlockCopy(aes.IV, 0, res, 0, aes.IV.Length); Buffer.BlockCopy(encBytes, 0, res, aes.IV.Length, encBytes.Length); return res; } } } public static byte[] Decrypt(string password, byte[] passwordSalt, byte[] cipherText) { using (var aes = createAes(password, passwordSalt)) { var iv = new byte[aes.IV.Length]; Buffer.BlockCopy(cipherText, 0, iv, 0, iv.Length); aes.IV = iv; // Probably could copy right to the byte array, but that's not guaranteed using (var dec = aes.CreateDecryptor()) { var decBytes = dec.TransformFinalBlock(cipherText, iv.Length, cipherText.Length - iv.Length); // Verify hash var hash = computeHash(decBytes, HASH_SIZE, decBytes.Length - HASH_SIZE); var existingHash = new byte[HASH_SIZE]; Buffer.BlockCopy(decBytes, 0, existingHash, 0, HASH_SIZE); if (!compareBytes(existingHash, hash)){ throw new CryptographicException("Message hash incorrect."); } // Hash is valid, we're done var res = new byte[decBytes.Length - HASH_SIZE]; Buffer.BlockCopy(decBytes, HASH_SIZE, res, 0, res.Length); return res; } } } static bool compareBytes(byte[] a1, byte[] a2) { if (a1.Length != a2.Length) return false; for (int i = 0; i < a1.Length; i++) { if (a1[i] != a2[i]) return false; } return true; } static Aes createAes(string password, byte[] salt) { // Salt may not be needed if password is safe if (password.Length < 8) throw new ArgumentException("Password must be at least 8 characters.", "password"); if (salt.Length < 8) throw new ArgumentException("Salt must be at least 8 bytes.", "salt"); var pdb = new PasswordDeriveBytes(password, salt, "SHA512", 129); var key = pdb.GetBytes(16); var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Key = pdb.GetBytes(aes.KeySize / 8); return aes; } static byte[] computeHash(byte[] data, int offset, int count) { using (var sha = SHA256.Create()) { return sha.ComputeHash(data, offset, count); } } public static void Main() { var password = "1234567890!"; var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; var ct1 = Encrypt(password, salt, Encoding.UTF8.GetBytes("Alice; Bob; Eve;: PerformAct1")); Console.WriteLine(Convert.ToBase64String(ct1)); var ct2 = Encrypt(password, salt, Encoding.UTF8.GetBytes("Alice; Bob; Eve;: PerformAct2")); Console.WriteLine(Convert.ToBase64String(ct2)); var pt1 = Decrypt(password, salt, ct1); Console.WriteLine(Encoding.UTF8.GetString(pt1)); var pt2 = Decrypt(password, salt, ct2); Console.WriteLine(Encoding.UTF8.GetString(pt2)); // Now check tampering try { ct1[30]++; Decrypt(password, salt, ct1); Console.WriteLine("Error: tamper detection failed."); } catch (Exception ex) { Console.WriteLine("Success: tampering detected."); Console.WriteLine(ex.ToString()); } } }
输出:
JZVaD327sDmCmdzY0PsysnRgHbbC3eHb7YXALb0qxFVlr7Lkj8WaOZWc1ayWCvfhTUz/y0QMz + uv0PwmuG8VBVEQThaNTD02JlhIs1DjJtg = QQvDujNJ31qTu/foDFUiVMeWTU0jKL/UJJfFAvmFtz361o3KSUlk/ZH + 4701mlFEU4Ce6VuAAuaiP1EENBJ74Wc8mE/QTofkUMHoa65/5E4 =爱丽丝 鲍勃; Eve;:PerformAct1 Alice; 鲍勃; Eve;:PerformAct2成功:检测到篡改.System.Security.Cryptography.CryptographicException:消息哈希不正确.at AesDemo.Decrypt(String password,Byte [] passwordSalt,Byte [] cipherText)在C:\ Program.cs:第46行,AesDemo.Main()在C:\ Program.cs:第100行
删除随机IV和哈希后,这是输出的类型:
tZfHJSFTXYX8V38AqEfYVXU5Dl/meUVAond70yIKGHY = tZfHJSFTXYX8V38AqEfYVcf9a3U8vIEk1LuqGEyRZXM =
注意第一个块是如何对应的"Alice; Bob; Eve;" 是一样的.确实是"角落案".
这是传递64位整数的简单示例.只是加密,你就会受到攻击.事实上,即使使用CBC填充,攻击也很容易完成.
public static void Main() { var buff = new byte[8]; new Random().NextBytes(buff); var v = BitConverter.ToUInt64(buff, 0); Console.WriteLine("Value: " + v.ToString()); Console.WriteLine("Value (bytes): " + BitConverter.ToString(BitConverter.GetBytes(v))); var aes = Aes.Create(); aes.GenerateIV(); aes.GenerateKey(); var encBytes = aes.CreateEncryptor().TransformFinalBlock(BitConverter.GetBytes(v), 0, 8); Console.WriteLine("Encrypted: " + BitConverter.ToString(encBytes)); var dec = aes.CreateDecryptor(); Console.WriteLine("Decrypted: " + BitConverter.ToUInt64(dec.TransformFinalBlock(encBytes, 0, encBytes.Length), 0)); for (int i = 0; i < 8; i++) { for (int x = 0; x < 250; x++) { encBytes[i]++; try { Console.WriteLine("Attacked: " + BitConverter.ToUInt64(dec.TransformFinalBlock(encBytes, 0, encBytes.Length), 0)); return; } catch { } } } }
输出:
价值:6598637501946607785价值
(字节):A9-38-19-D1-D8-11-93-5B
加密:
31-59-B0-25-FD-C5-13-D7-81-D8-F5-8A-33-2A-57-DD
解密:6598637501946607785
遭到攻击:14174658352338201502
因此,如果这是您要发送的ID类型,则可以很容易地将其更改为其他值.您需要在邮件之外进行身份验证.有时,消息结构不太可能落实到位,并且可以作为一种保护措施,但为什么要依赖可能发生变化的事情呢?无论应用程序如何,您都需要能够依赖加密才能正常工作.