2

I need to pass a URL as a parameter into my querystring, since the URLs can be long I need to shorten the URL while passing and then be able to decrypt them on server side.

The URL that I am trying to pass does not contain sensitive information so string encryption techniques are not required, I am just looking to convert a long string to a short string and be able to reconstruct it back to a string.

I have tried AES encryption and it works but the resulting string is sometimes longer than the URL value itself.

Example of what I've tried so far :

private static byte[] key = { 252, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private static byte[] vector = { 152, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 };
private ICryptoTransform encryptor, decryptor;
private UTF8Encoding encoder;

public SimpleAES()
{
    RijndaelManaged rm = new RijndaelManaged();
    encryptor = rm.CreateEncryptor(key, vector);
    decryptor = rm.CreateDecryptor(key, vector);
    encoder = new UTF8Encoding();
}

public string Encrypt(string unencrypted)
{
    return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
}

public string Decrypt(string encrypted)
{
    return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
}

public string EncryptToUrl(string unencrypted)
{ 
    return HttpUtility.UrlEncode(Encrypt(unencrypted));
}

public string DecryptFromUrl(string encrypted)
{
    return Decrypt(HttpUtility.UrlDecode(encrypted));
}

public byte[] Encrypt(byte[] buffer)
{
    return Transform(buffer, encryptor);
}

public byte[] Decrypt(byte[] buffer)
{
    return Transform(buffer, decryptor);
}

protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
{
    MemoryStream stream = new MemoryStream();
    using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
    {
        cs.Write(buffer, 0, buffer.Length);
    }
    return stream.ToArray();
}

Example TEST :

string unencrypted = "/exampleurl/this_is_a_long_string_the_length_of_this_url_is_112_charachters_/this_string_needs_to_be-shortened/"; 

var result = EncryptToUrl(unencrypted);    
"MHMyQdwbJpw8ah%2fbhAr2eJwTFa%2fyupemjuOVcBJmxTIdzcR0PZKCNSa5Fvi7kNrY3Kxlk5KWqAAEspWVtJfNjwwPs%2bCDGpC9Fn8CeGezWhXEbLT6CST2v%2fKpvptHVi3fBYSk1w3q1FYMx3C5DdKueQ%3d%3d" 

The actual string is 112 charachters long and the result is 165 charahcters long.

GenericJon
  • 8,746
  • 4
  • 39
  • 50
Murtaza Mandvi
  • 10,708
  • 23
  • 74
  • 109
  • 1
    I don't understand. Why do you tink that encryption will shorten anything? There really are only two options: compression, but this is unlikely to benefit you in the case of URLs, and URL shortening services, that really just store the long URL in a database, and the short one performs a lookup. – Kris Vandermotten Nov 07 '13 at 16:10
  • Why do you think that your URL needs to be shortened? – Peter M Nov 07 '13 at 16:11
  • @PeterM - because we do not want 2048 character long urls being passed as a single parameter – Murtaza Mandvi Nov 07 '13 at 16:14
  • 2
    Look into compression, not into encryption; also if urls are from fix set you can have associative table on server side (like 1 = "very very long url", 2 = "another very long url") and pass the url like /exampleurl/1 and /exampleurl/2 – Ondrej Svejdar Nov 07 '13 at 16:16
  • @OndrejSvejdar since this being a web service module , lots of clients call the service from different domains, impossible to maintain a lookup table. – Murtaza Mandvi Nov 07 '13 at 16:18
  • 1
    Encryption will never reduce the size of a set of data. The reason is that encryption is lossless and usually adds a form of padding to align with the internal cipher block size. Additionally, a given mode of operation in a cipher may add extra information like initialization vectors or hashes. Sometimes people compress data and then encrypt it, to reduce the chance of having duplicate block inputs and thus slightly improve cryptographic strength. – Michael J. Gray Nov 07 '13 at 16:19
  • 6
    It's worth asking: can you pass this as form data via a HTTP POST instead of in the querystring? – gooid Nov 07 '13 at 16:21

2 Answers2

3

The following code is taken verbatim from here. I duplicated this because the question is not a duplicate but the answer solves the problem this question poses. When you call Zip you will need to base64 encode the result to make it friendly for a browser if you plan to include it in a URL or something.

public static void CopyTo(Stream src, Stream dest) {
    byte[] bytes = new byte[4096];

    int cnt;

    while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) {
        dest.Write(bytes, 0, cnt);
    }
}

public static byte[] Zip(string str) {
    var bytes = Encoding.UTF8.GetBytes(str);

    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream()) {
        using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
            //msi.CopyTo(gs);
            CopyTo(msi, gs);
        }

        return mso.ToArray();
    }
}

public static string Unzip(byte[] bytes) {
    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream()) {
        using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
            //gs.CopyTo(mso);
            CopyTo(gs, mso);
        }

        return Encoding.UTF8.GetString(mso.ToArray());
    }
}

static void Main(string[] args) {
    byte[] r1 = Zip("StringStringStringStringStringStringStringStringStringStringStringStringStringString");
    string r2 = Unzip(r1);
}
Community
  • 1
  • 1
Michael J. Gray
  • 9,784
  • 6
  • 38
  • 67
  • 1
    Encoding the byte[] to string would generate an even longer string. – Murtaza Mandvi Nov 07 '13 at 16:32
  • 1
    You're going to need to encode it somehow and in a lossless manner. So, either you can take your really long URL and compress it by 80% and then encode it to base64 for an average 40% penalty, thus still having a size loss, or you can just have really long URLs. Did you even try the example? – Michael J. Gray Nov 07 '13 at 16:46
1

This might sound strange, but can you store the querystring in a database and reference it by some primary key? That might be similar to using some third party URL shortening service.

Alex Dresko
  • 5,179
  • 3
  • 37
  • 57
  • As commented above : since this being a web service module , lots of clients call the service from different domains, impossible to maintain a lookup table. – Murtaza Mandvi Nov 07 '13 at 16:28
  • When you say "web service", do you mean that it is being called from code, or is it being used in the browser's address bar? Browser's have (or at least used to have) limitations on the length of a URL, but the HTTP protocol does not impose a limit. Therefore, there's really no need to shorten the URL if it's being called from code. – Alex Dresko Nov 07 '13 at 16:36
  • Client calls the service and passes URL as a query string parameter and we need the parameter on our side, client will "compress" the URL and we will "decompress" it on our side. – Murtaza Mandvi Nov 07 '13 at 16:38