AES在ASP.NET用VB.NET [英] AES in ASP.NET with VB.NET

查看:220
本文介绍了AES在ASP.NET用VB.NET的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是加密与AES的URL链接,用户名传递给使用VB.NET 2005 ASP.NET中的其他网站一个很好的链接或文章?
FYI:接收网站将能够访问私钥来解密

What is a good link or article on encrypting a URL link with AES to pass username to another web site in ASP.NET using VB.NET 2005? FYI: The receiving web site will have access to the private KEY to decrypt.

推荐答案

不要这么做!编写自己的加密系统可以很容易导致决策失误。最好是使用现有的系统,如果还是不行,找人谁知道加密来做到这一点。如果你必须自己做,阅读实用加密

First

Don't do it! Writing your own crypto system can easily lead to making mistakes. It's best to use an existing system, or if not, get someone who knows cryptography to do it. If you have to do it yourself, read Practical Cryptography.

和请记住:我们已经有了足够快,不安全的系统(布鲁斯) - 做正确的事情,并担心以后的表现。

And please, remember: "We already have enough fast, insecure systems." (Bruce Schneier) -- Do things correct and worry about performance later.

这是说,如果你坚持使用AES推出自己的,这里有几个三分球。

That said, if you are stuck on using AES to roll your own, here are a few pointers.

AES是一种分组密码。给定一个键和明文块,将它转换成一个特定的密文。这样做的问题是,相同的数据块将产生具有相同的密钥,每次相同的密文。因此,假设您发送的数据是这样的:

AES is a block cipher. Given a key and a block of plaintext, it converts it to a specific ciphertext. The problem with this is that the same blocks of data will generate the same ciphertext with the same key, every time. So suppose you send data like this:

用户=加密(用户名)及角色=加密(的UserRole)

user=Encrypt(Username)&roles=Encrypt(UserRoles)

他们是两个独立的模块,每一次加密的UserRole将具有相同的密文,无论名称。所有我需要的是一个管理员密文,我可以放弃它的权利与我cipher'd用户名。哎呀。

They're two separate blocks, and the UserRoles encryption will have the same ciphertext each time, regardless of the name. All I need is the ciphertext for an admin, and I can drop it right in with my cipher'd username. Oops.

因此​​,有加密操作模式的。其主要思想是,你需要一个块的密文,并XOR到下一个块的密文。这样,我们会做加密(的UserRole,用户名),以及用户名密文被影响的UserRole

So, there are cipher operation modes. The main idea is that you'll take the ciphertext of one block, and XOR it into the ciphertext of the next block. That way we'll do Encrypt(UserRoles, Username), and the Username ciphertext is affected by the UserRoles.

问题是,第一座仍然脆弱 - 只要看到别人的密文,我可能知道自己的角色。进入初始化向量。的IV启动的密码,并确保其具有随机数据流的其余部分进行加密。所以,现在的密文的UserRole具有随机IV异或的密文。问题解决了。

The problem is that the first block is still vulnerable - just by seeing someone's ciphertext, I might know their roles. Enter the initialization vector. The IV "starts up" the cipher and ensures it has random data to encrypt the rest of the stream. So now the UserRoles ciphertext has the ciphertext of the random IV XOR'd in. Problem solved.

所以,一定要为每一个消息的随机IV。 IV是不敏感,并且可以与所述密文明文发送。使用足够大的IV - 块的大小应为许多情况下是罚款

So, make sure you generate a random IV for each message. The IV is not sensitive and can be sent plaintext with the ciphertext. Use an IV large enough -- the size of the block should be fine for many cases.

AES不提供完整的功能。任何人都可以修改您的密文,而解密仍然可以工作。这是不太可能这将是的一般有效的数据,但它可能很难知道有效的数据是什么。举例来说,如果你发送加密的GUID,它会很容易修改某些位,并生成一个完全不同的。这可能导致应用程序错误等。

AES doesn't provide integrity features. Anyone can modify your ciphertext, and the decrypt will still work. It's unlikely it'll be valid data in general, but it might be hard to know what valid data is. For instance, if you're transmitting a GUID encrypted, it'd be easy to modify some bits and generate a completely different one. That could lead to application errors and so on.

此修复程序有运行在明文散列算法(SHA256使用或SHA512),并包括在数据传输你。所以,如果我的信息是(用户名,角色),你会发送(用户名,角色,哈希(用户名,角色))。现在,如果有人通过翻转位密文篡改,散列将不再计算,你可以拒绝该邮件。

The fix there is to run a hash algorithm (use SHA256 or SHA512) on the plaintext, and include that in the data you transmit. So if my message is (UserName, Roles), you'll send (UserName, Roles, Hash(UserName, Roles)). Now if someone tampers with the ciphertext by flipping a bit, the hash will no longer compute and you can reject the message.

如果你需要生成从密码密钥,使用内置类:<一href=\"http://msdn.microsoft.com/en-us/library/system.security.cryptography.passwordderivebytes.aspx\">System.Security.Cryptography.PasswordDeriveBytes.这提供了盐和迭代,这可以提高衍生键的强度,减少如果密钥被泄露发现密码的机会。

If you need to generate a key from a password, use the built-in class: System.Security.Cryptography.PasswordDeriveBytes. This provides salting and iterations, which can improve the strength of derived keys and reduce the chance of discovering the password if the key is compromised.

编辑:对不起,不提这个早些时候:P。你还需要确保你有一个反重放系统。如果你简单地加密消息,并通过它,谁得到消息可以只重新发送。为了避免这种情况,你应该添加一个时间戳的消息。如果时间戳是由一个特定的阈值不同,则拒绝该消息。您可能还需要包括它一次性ID(这可能是四),并拒绝来自使用相同的ID其他IP时有效信息。

Sorry for not mentioning this earlier :P. You also need to make sure you have an anti-replay system. If you simply encrypt the message and pass it around, anyone who gets the message can just resend it. To avoid this, you should add a timestamp to the message. If the timestamp is different by a certain threshold, reject the message. You may also want to include a one-time ID with it (this could be the IV) and reject time-valid messages that come from other IPs using the same ID.

要确保你的哈希验证时,您包括定时信息是非常重要的。否则,有人可能会用一个位密文篡改,并可能产生一个有效的时间戳,如果你没有检测到这种暴力的企图。

It's important to make sure you do the hash verification when you include the timing information. Otherwise, someone could tamper with a bit of the ciphertext and potentially generate a valid timestamp if you don't detect such brute force attempts.

由于显然使用的是正确IV是有争议的一些人,这里的一些code,它会生成随机的IV,并将它们添加到您的输出为您服务。它也将执行身份验证步骤,确保加密的数据没有被修改。

Since apparently using an IV correctly is controversial for some folks, here's some code that'll generate random IVs and add them to your output for you. It'll also perform the authentication step, making sure the encrypted data wasn't modified.

using System;
using System.Security.Cryptography;
using System.Text;

class AesDemo {

    const int HASH_SIZE = 32; //SHA256

    /// <summary>Performs encryption with random IV (prepended to output), and includes hash of plaintext for verification.</summary>
    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=
  爱丽丝;鲍勃;夏娃;: PerformAct1爱丽丝;
  鲍勃;夏娃;: PerformAct2成功:
  篡改检测。
  System.Security.Cryptography.CryptographicException:
  消息哈希不正确。在
  AesDemo.Decrypt(字符串密码,
  字节] passwordSalt,字节]
  密文)在
  C:\\的Program.cs:行
  46在AesDemo.Main()的
  C:\\的Program.cs:行
  100

JZVaD327sDmCmdzY0PsysnRgHbbC3eHb7YXALb0qxFVlr7Lkj8WaOZWc1ayWCvfhTUz/y0QMz+uv0PwmuG8VBVEQThaNTD02JlhIs1DjJtg= QQvDujNJ31qTu/foDFUiVMeWTU0jKL/UJJfFAvmFtz361o3KSUlk/zH+4701mlFEU4Ce6VuAAuaiP1EENBJ74Wc8mE/QTofkUMHoa65/5e4= Alice; Bob; Eve;: PerformAct1 Alice; Bob; Eve;: PerformAct2 Success: tampering detected. System.Security.Cryptography.CryptographicException: Message hash incorrect. at AesDemo.Decrypt(String password, Byte[] passwordSalt, Byte[] cipherText) in C:\Program.cs:line 46 at AesDemo.Main() in C:\Program.cs:line 100

删除随机IV和散列后,这里的输出类型:

After removing the random IV and the hash, here's the type of output:

tZfHJSFTXYX8V38AqEfYVXU5Dl / meUVAond70yIKGHY =
  tZfHJSFTXYX8V38AqEfYVcf9a3U8vIEk1LuqGEyRZXM =

tZfHJSFTXYX8V38AqEfYVXU5Dl/meUVAond70yIKGHY= tZfHJSFTXYX8V38AqEfYVcf9a3U8vIEk1LuqGEyRZXM=

注意如何第一个块,对应于爱丽丝鲍伯;除夕;是相同的。 拐角情况确实如此。

Notice how the first block, corresponding to "Alice; Bob; Eve;" is the same. "Corner case" indeed.

下面是传递一个64位整数的简单例子。只是加密和你开的攻击。事实上,攻击是很容易做到,即使CBC填充。

Here's a simple example of passing a 64-bit integer. Just encrypt and you're open to attack. In fact, the attack is easily done, even with CBC padding.

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值

Value: 6598637501946607785 Value

(字节):A9-38-19-D1-D8-11-93-5B

(bytes): A9-38-19-D1-D8-11-93-5B

加密:

31-59-B0-25-FD-C5-13-D7-81-D8-F5-8A-33-2A-57-DD

31-59-B0-25-FD-C5-13-D7-81-D8-F5-8A-33-2A-57-DD

解密:6598637501946607785

Decrypted: 6598637501946607785

遇袭:14174658352338201502

Attacked: 14174658352338201502

所以,如果这是那种你要发送的ID,它可以很容易地修改为其他值。您需要将您的信息以外的身份验证。有时,消息结构是不可能陷入的地方,可以八九不离十作为保障,但为何依靠的东西,可能会改变?你需要能够依靠你的密码,无论正常运行的应用程序。

So, if that's the kind of ID you're sending, it could quite easily be changed to another value. You need to authenticate outside of your message. Sometimes, the message structure is unlikely to fall into place and can sorta act as a safeguard, but why rely on something that could possibly change? You need to be able to rely on your crypto working correctly regardless of the application.

这篇关于AES在ASP.NET用VB.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆