20

I need to send a string of about 30 chars over the internet which will probably end up as an ID in a another company's database.

While the string itself will not be identifying, I would still like it not to be recognisable in any way.

What is the easiest way to obfuscate such a string in .NET, so that it can be easily reversed when necessary?

Paul Lassiter
  • 2,641
  • 5
  • 22
  • 25

4 Answers4

30

THIS IS NOT CRYPTOGRAPHY

Do not use this answer for any information that must be kept secret.

It will make a string hard for a human to read.

It will round-trip but not may not if your string is not "vanilla" and you use a large value for shift.

This code will not protect the data from a concerted effort to "crack" it. An intelligent and skilled human can decode this with pen and paper.

Original answer follows below.

How about something classical (with a modern twist).

public static string Caesar(this string source, Int16 shift)
{
    var maxChar = Convert.ToInt32(char.MaxValue);
    var minChar = Convert.ToInt32(char.MinValue);

    var buffer = source.ToCharArray();

    for (var i = 0; i < buffer.Length; i++)
    {
        var shifted = Convert.ToInt32(buffer[i]) + shift;

        if (shifted > maxChar)
        {
            shifted -= maxChar;
        }
        else if (shifted < minChar)
        {
            shifted += maxChar;
        }

        buffer[i] = Convert.ToChar(shifted);
    }

    return new string(buffer);
}

Which obviously you would use like this

var plain = "Wibble";
var caesered = plain.Caesar(42);
var newPlain = caesered.Caesar(-42);

Its quick, your key is just an Int16 and it will prevent the casual observer from copy pasting the value but, its not secure.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • - I like this :) say I was storing this string in an html page and wanted to unCeaser and use the string via javascript, can you show me how that would work ? – Martin Sansone - MiOEE Nov 18 '13 at 18:59
  • 1
    @TheDonSansone, that could be tricky. Whilst I could write a javascript equivalent of this function, some combination of `shift` and unicode could produce `char` values that don't map to real unicode code points.This is fine if the data is transfered as binary between to .Net components but when this is returned via HTTP to an unknown browser I can't be certain what will happen. If you can limit the range of char values in your string and the magnitude of `shift` you'd probably be ok but I'd be tempted to find a "cast iron" alternative. – Jodrell Nov 19 '13 at 09:31
  • Jodrell understood, cast iron alternative has been found ;) thanks again. – Martin Sansone - MiOEE Nov 20 '13 at 01:53
  • Will this work with any string? For example strings containing Chinese characters? – chriscode Aug 22 '23 at 09:19
  • @chriscode maybe but in practice, you might as well just use some built in encoding or encryption with a hardcoded key. That will definitely work. – Jodrell Aug 22 '23 at 14:32
  • @chriscode, I put a disclaimer on the answer. – Jodrell Aug 22 '23 at 14:53
11

How about:

    Convert.ToBase64String(Encoding.UTF8.GetBytes(myString));

and its converse:

    Encoding.UTF8.GetString(Convert.FromBase64String(myObfuscatedString));

as long as you don't mind an increase in the length of your string

Joe
  • 122,218
  • 32
  • 205
  • 338
  • 12
    The only downside, apart from the size increase, is the tale tale `==` terminator that always makes me think, that must be base64. – Jodrell Oct 23 '12 at 08:54
  • @Joe Can you explain a little bit what this obfuscation does (in term of bits)? – user2997779 Feb 20 '17 at 15:19
  • @user2997779 - it does what it says on the tin: converts the string to base64 encoding, an encoding about which you will find plenty of documentation if you look. Base64 encoding is not easily readable by most humans, thus providing a basic level of obfuscation, but this technique does not pretend to be secure. – Joe Feb 20 '17 at 16:18
  • 3
    @rolls - IMHO if you care about whether the algorithm can be easily guessed, you should be using encryption rather than obfuscation. – Joe Sep 02 '17 at 09:05
  • 1
    This is perfect for obfuscation. I want to mask a file path + hash payload in a simple id string that needs to look clean, encryption isn't always about security per se. – Shukri Adams Feb 06 '19 at 20:44
6

Try encrypting it with for example AES, if you know the encrypt key on the other machine you can easily decrypt it there

http://msdn.microsoft.com/en-us/library/system.security.cryptography.aes(v=vs.100).aspx

There are many code samples around. For example i found this post by a quick search, even though it's only 128 bit i think it should do the trick

Using AES encryption in C#

Community
  • 1
  • 1
middelpat
  • 2,555
  • 1
  • 20
  • 29
  • but where will you store the key? – Jodrell Oct 23 '12 at 08:09
  • This is two-way, 'unbreakable' and simple to implement (as opposed to writing your own 'encryptor'). – g t Oct 23 '12 at 08:10
  • Your application configuration files like in asp for example appsettings – middelpat Oct 23 '12 at 08:10
  • Key can be hard-coded - if it's only to stop the string being visible in a 3rd-party database. – g t Oct 23 '12 at 08:11
  • @gt, the unbreakable claim is moot when the key is hardcoded. – Jodrell Oct 23 '12 at 08:50
  • @Jodrell, you're absolutely correct - but only if the DLL doing the decoding is sent to the 3rd party and decompiled (or the key becomes public knowledge). To the casual observer, the keys will be 'unbreakable'. If the data is sensitive however, then this method will be insecure, but no more so than, say, using a simple Caesar cipher ;) – g t Oct 23 '12 at 09:21
3

I was inspired by the answer by @Jodrell, and here's my alternative version. The only real difference is that I use the modulo operator instead of the if-then-else construction.

And if you, like me, had never heard of the Caesar Cipher before, here's a link:

https://en.wikipedia.org/wiki/Caesar_cipher

   public static partial class MString
   {
      ...

      /// <summary>
      /// Method to perform a very simple (and classical) encryption for a string. This is NOT at 
      /// all secure, it is only intended to make the string value non-obvious at a first glance.
      ///
      /// The shiftOrUnshift argument is an arbitrary "key value", and must be a non-zero integer 
      /// between -65535 and 65535 (inclusive). To decrypt the encrypted string you use the negative 
      /// value. For example, if you encrypt with -42, then you decrypt with +42, or vice-versa.
      ///
      /// This is inspired by, and largely based on, this:
      /// https://stackoverflow.com/a/13026595/253938
      /// </summary>
      /// <param name="inputString">string to be encrypted or decrypted, must not be null</param>
      /// <param name="shiftOrUnshift">see above</param>
      /// <returns>encrypted or decrypted string</returns>
      public static string CaesarCipher(string inputString, int shiftOrUnshift)
      {
         // Check C# is still C#
         Debug.Assert(char.MinValue == 0 && char.MaxValue == UInt16.MaxValue);

         const int C64K = UInt16.MaxValue + 1;

         // Check the arguments
         if (inputString == null)
            throw new ArgumentException("Must not be null.", "inputString");
         if (shiftOrUnshift == 0)
            throw new ArgumentException("Must not be zero.", "shiftOrUnshift");
         if (shiftOrUnshift <= -C64K || shiftOrUnshift >= C64K)
            throw new ArgumentException("Out of range.", "shiftOrUnshift");

         // Perform the Caesar cipher shifting, using modulo operator to provide wrap-around
         char[] charArray = new char[inputString.Length];
         for (int i = 0; i < inputString.Length; i++)
         {
            charArray[i] = 
                  Convert.ToChar((Convert.ToInt32(inputString[i]) + shiftOrUnshift + C64K) % C64K);
         }

         // Return the result as a new string
         return new string(charArray);
      }

      ...
   }

And a bit of test code:

     // Test CaesarCipher() method
     const string CHelloWorld = "Hello world!";
     const int CCaesarCipherKey = 42;
     string caesarCiphered = MString.CaesarCipher(CHelloWorld, CCaesarCipherKey);
     if (MString.CaesarCipher(caesarCiphered, -CCaesarCipherKey) != CHelloWorld)
        throw new Exception("Oh no!");
RenniePet
  • 11,420
  • 7
  • 80
  • 106