查询字符串参数混淆

RuS*_*uSh 7 .net c# asp.net encryption cryptography

我想在ASP.NET中混淆一个查询字符串参数.该站点将有大量请求,因此算法不应该太慢.

我的问题是我找到的所有算法都会产生不需要的字符(比如+/=)

这是我想要实现的一个例子:

www.domain.com/?id=1844
Run Code Online (Sandbox Code Playgroud)

www.domain.com/?id=3GQ5DTL3oVd91WsGj74gcQ
Run Code Online (Sandbox Code Playgroud)

混淆的参数应该只包括az和AZ以及0-9个字符.

我知道我可以使用base64进行加密,但这会生成不需要的字符,例如/or =+.

知道可以使用什么算法吗?

更新: 我知道UrlEncoding,我想避免编码字符串.因为这会在网址中生成%F2或%B2等字符.

Dav*_*ter 5

你可以使用HttpServerUtility.UrlTokenEncodeHttpServerUtility.UrlTokenDecode

Encode使用base64编码,但替换URL不友好的字符.

之前的SO问题中有类似的答案.看到接受的答案.


Lun*_*ist 5

您可以使用三重DES来使用narow分组密码对值进行编码.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                }
            }
            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Encryptor = TDes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            return ToHex(OutputBuffer);
        }
        static long Decode(string value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;

            for (int i = 0; i < 8; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Decryptor = TDes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    return ((long*)pOutputBuffer)[0];
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue = Decode(EncodedValue, Key);
            Console.WriteLine("The decoded result is {0}.", DecodedValue);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出应该是这样的:

Number to encode = 873435734.
Key to encode with is 38137b6a7aa49cc6040c4297064fdb4461c79a895f40b4d1.
The encoded value is 43ba3fb809a47b2f.
The decoded result is 873435734.
Run Code Online (Sandbox Code Playgroud)

请注意,编码值仅为16个字符宽.

如果您真的对滥用行为有所了解,那么可以以类似的方式使用AES.在下一个例子中,我切换AES并将64位id号写入块的两侧.如果它没有在两侧以相同的值进行解码,那么它将被拒绝.这可以防止人们以随机数写入.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                    ((long*)pInputBuffer)[1] = value;
                }
            }
            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Encryptor = Aes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            return ToHex(OutputBuffer);
        }
        static bool TryDecode(string value, byte[] key, out long result) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;

            for (int i = 0; i < 16; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Decryptor = Aes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    //return ((long*)pOutputBuffer)[0];
                    if (((long*)pOutputBuffer)[0] == ((long*)pOutputBuffer)[1]) {
                        result = ((long*)pOutputBuffer)[0];
                        return true;
                    }
                    else {
                        result = 0;
                        return false;
                    }
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue;
            bool Success = TryDecode(EncodedValue, Key, out DecodedValue);
            if (Success) {
                Console.WriteLine("Successfully decoded the encoded value.");
                Console.WriteLine("The decoded result is {0}.", DecodedValue);
            }
            else
                Console.WriteLine("Failed to decode encoded value. Invalid result.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果应该看起来像这样:

Number to encode = 1795789891.
Key to encode with is 6c90323644c841a00d40d4407e23dbb2ab56530e1a4bae43.
The encoded value is 731fceec2af2fcc2790883f2b79e9a01.
Successfully decoded the encoded value.
The decoded result is 1795789891.
Run Code Online (Sandbox Code Playgroud)

另请注意,由于我们现在使用了更宽的分组密码,因此编码值现在为32个字符宽.

  • @Lunatic,@ sharru:[既不需要循环也不安全阻塞](http://stackoverflow.com/questions/4882378/convert-pointer-to-loop-option-in-c),`System.BitConverter`将做得非常好. (4认同)