C# change the first 32bit Int of a GUID - c#

I have a GUID which I created with GUID.NewGUID(). Now I want to replace the first 32 bit of it with a specific 32-bit Integer while keeping the rest as they are.
Is there a function to do this?

You can use ToByteArray() function and then the Guid constructor.
byte[] buffer = Guid.NewGuid().ToByteArray();
buffer[0] = 0;
buffer[1] = 0;
buffer[2] = 0;
buffer[3] = 0;
Guid guid = new Guid(buffer);

Since the Guid struct has a constructor that takes a byte array and can return its current bytes, it's actually quite easy:
//Create a random, new guid
Guid guid = Guid.NewGuid();
Console.WriteLine(guid);
//The original bytes
byte[] guidBytes = guid.ToByteArray();
//Your custom bytes
byte[] first4Bytes = BitConverter.GetBytes((UInt32) 0815);
//Overwrite the first 4 Bytes
Array.Copy(first4Bytes, guidBytes, 4);
//Create new guid based on current values
Guid guid2 = new Guid(guidBytes);
Console.WriteLine(guid2);
Fiddle
Keep in mind however, that the order of bytes returned from BitConverter depends on your processor architecture (BitConverter.IsLittleEndian) and that your Guid's entropy decreases by 232 if you use the same number every time (which, depending on your application might not be as bad as it sounds, since you have 2128 to begin with).

The question is about replacing bits, but if someone wants to replace first characters of guid directly, this can be done by converting it to string, replacing characters in string and converting back. Note that replaced characters should be valid in hex, i.e. numbers 0 - 9 or letters a - f.
var uniqueGuid = Guid.NewGuid();
var uniqueGuidStr = "1234" + uniqueGuid.ToString().Substring(4);
var modifiedUniqueGuid = Guid.Parse(uniqueGuidStr);

Related

Get a guid to encode using big-endian formatting C#

I have a unusual situation where by I have an existing MySQL database that uses binary(16) primary keys, these are the basis for UUIDs that are used in an existing api.
My problem is that I now want to add a replacement api written with dotnet core, and I'm running into a problem with encoding that has been explained here
Specifically, the Guid struct in dotnet uses a mixed-endian format that produces a different string to the existing api. This isn't acceptable for obvious reasons.
So my question is this: is there an elegant way to force the Guid struct to encode entirely with the big-endian format?
If there isn't I can just write a terrible hack, but I thought I'd check with the collective intelligence of the SO community first!
Nope; as far as I'm aware there's no inbuilt way to get this. And yes, Guid has what I can only call "crazy-endian" implementation currently. You'd need to get the Guid-ordered bits (either via unsafe or Guid.ToByteArray) and then order them manually, figuring out which chunks to reverse - it isn't a simple Array.Reverse(). So: very manual, I'm afraid. I suggest using a guid like
00010203-0405-0607-0809-0a0b0c0d0e0f
to debug it; this gives you (as I suspect you are aware):
03-02-01-00-05-04-07-06-08-09-0A-0B-0C-0D-0E-0F
so:
reverse 4
reverse 2
reverse 2
straight 8
As of 2021 there still isn't a built-in way to convert a System.Guid to a MySQL compatible big endian string in C#.
Here's the extension we came up with when we encountered this exact C# mixed-endian Guid problem at work:
public static string ToStringBigEndian(this Guid guid)
{
// allocate enough bytes to store Guid ASCII string
Span<byte> result = stackalloc byte[36];
// set all bytes to 0xFF (to be able to distinguish them from real data)
result.Fill(0xFF);
// get bytes from guid
Span<byte> buffer = stackalloc byte[16];
_ = guid.TryWriteBytes(buffer);
int skip = 0;
// iterate over guid bytes
for (int i = 0; i < buffer.Length; i++)
{
// indices 4, 6, 8 and 10 will contain a '-' delimiter character in the Guid string.
// --> leave space for those delimiters
if (i is 4 or 6 or 8 or 10)
{
skip++;
}
// stretch high and low bytes of every single byte into two bytes (skipping '-' delimiter characters)
result[(2 * i) + skip] = (byte)(buffer[i] >> 0x4);
result[(2 * i) + 1 + skip] = (byte)(buffer[i] & 0x0Fu);
}
// iterate over precomputed byte array.
// values 0x0 to 0xF are final hex values, but must be mapped to ASCII characters.
// value 0xFF is to be mapped to '-' delimiter character.
for (int i = 0; i < result.Length; i++)
{
// map bytes to ASCII values (a-f will be lowercase)
ref byte b = ref result[i];
b = b switch
{
0xFF => 0x2D, // Map 0xFF to '-' character
< 0xA => (byte)(b + 0x30u), // Map 0x0 - 0x9 to '0' - '9'
_ => (byte)(b + 0x57u) // Map 0xA - 0xF to 'a' - 'f'
};
}
// get string from ASCII encoded guid byte array
return Encoding.ASCII.GetString(result);
}
it's a bit lengthy but apart from the big endian string it returns it does no heap allocations so it's guaranteed to be fast :)

Generate Deterministic Guid from a List of Guids

I would like to generate a Guid from a list of other Guids. The generated Guid must have the property that for the same input list of guids the resulting Guid will be the same, no matter how many times I apply the transformation.
Also, it should have the lowest collision possible so different guids at the input generate a different guid at the output.
Can someone help me with this? What should be the best way to go here? It's basically a hash function but over Guids.
You could do some arithmetic on the individual bytes of a Guid - the code below basically adds them up (modulo 256 because of the overflow):
byte[] totalBytes = new byte[16];
foreach (var guid in guids) {
var bytes = guid.ToByteArray();
for (int i = 0; i < 16; i++) {
totalBytes[i] += bytes[i];
}
}
var totalGuid = new Guid(totalBytes);

Is there any way to create a short unique code like short GUID?

I want to create a short GUID. Is there any way to create a short unique code like short GUID?
I want to create a ticket tracking number.
The length of GUID is 128bits(16bytes), so if you want to create a short GUID , you have to change GUID's encoding.
For instance, you can use base64 or ASCII85.
/// <summary>
/// Creates a GUID which is guaranteed not to equal the empty GUID
/// </summary>
/// <returns>A 24 character long string</returns>
public static string CreateGuid()
{
Guid guid = Guid.Empty;
while (Guid.Empty == guid)
{
guid = Guid.NewGuid();
}
// Uses base64 encoding the guid.(Or ASCII85 encoded)
// But not recommend using Hex, as it is less efficient.
return Convert.ToBase64String(guid.ToByteArray());
}
Jeff Atwood has an article on his blog how to shorten a GUID to 20 characters without losing information:
Coding Horror: Equipping our ASCII Armor
unique within one year, visibly 'random'
string UniqueID()
{
var t = DateTime.UtcNow;
long dgit = t.Millisecond * 1000000000L +
t.DayOfYear * 1000000L +
t.Hour * 10000L +
t.Minute * 100L +
t.Second;
return Convert.ToBase64String(BitConverter.GetBytes(dgit).Take(5).ToArray()).TrimEnd('=');
}
here's one with a customizable character set
string UniqueID(string CharList = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
{
var t = DateTime.UtcNow;
char[] charArray = CharList.ToCharArray();
var result = new Stack<char>();
var length = charArray.Length;
long dgit = 1000000000000L +
t.Millisecond * 1000000000L +
t.DayOfYear * 1000000L +
t.Hour * 10000L +
t.Minute * 100L +
t.Second;
while (dgit != 0)
{
result.Push(charArray[dgit % length]);
dgit /= length;
}
return new string(result.ToArray());
}
Really depends on your usage.
For example, if you were generating them at a pace less than 1 per second, you could just increment a 32bit int (1/4 the size of a 128bit GUID). That would last you a little over 68 years at the rate of 1 per second.
If you work out your usage, it should be pretty simple to work out the minimum size you can get away with. It will also depend if you want to be able to generate them anywhere, or if they will be generated by a single server or piece of software.
Try Base 36, to get unique number all you have to do is use an auto number, and save it as Base36. However in order for them to be random, you will need something else.
What I will do is, hash or encrypt the ticket number as ticket tracking code. Like,
code = Base36(MD5(ticketID+"my secrete"));
If you want tracking code to be unique then I will encrypt with some keys.
There is also am alternative library to convert Guid to a shorter 26-char text representation. Instead of Base64 encoding it uses Base32 dictionary, which is URL-safe and case-insensitive.
var guid = Guid.NewGuid(); // b392ebf5-88d3-49b9-9ad8-1d4a73431787
var shorterGuid = guid.ToShorterString(); // yrpt5gynl2wonaqs3p5baksrkw
NuGet link: https://www.nuget.org/packages/SourceExpress.ShorterGuid/
GitHub link: https://github.com/SourceExpress/shorter-guid

Encrypt a number to another number of the same length

I need a way to take a 12 digit number and encrypt it to a different 12 digit number (no characters other than 0123456789). Then at a later point I need to be able to decrypt the encrypted number back to the original number.
It is important that it isn't obvious if 2 encrypted numbers are in order. So for instance if I encrypt 0000000000001 it should look totally different when encrypted than 000000000002. It doesn't have to be the most secure thing in the world, but the more secure the better.
I've been looking around a lot but haven't found anything that seems to be a perfect fit. From what I've seen some type of XOR might be the easiest way to go, but I'm not sure how to do this.
Thanks,
Jim
I ended up solving this thanks to you guys using "FPE from a prefix cipher" from the wikipedia page http://en.wikipedia.org/wiki/Format-preserving_encryption. I'll give the basic steps below to hopefully be helpful for someone in the future.
NOTE - I'm sure any expert will tell you this is a hack. The numbers seemed random and it was secure enough for what I needed, but if security is a big concern use something else. I'm sure experts can point to holes in what I did. My only goal for posting this is because I would have found it useful when doing my search for an answer to the problem. Also only use this in situations where it couldn't be decompiled.
I was going to post steps, but its too much to explain. I'll just post my code. This is my proof of concept code I still need to clean up, but you'll get the idea. Note my code is specific to a 12 digit number, but adjusting for others should be easy. Max is probably 16 with the way I did it.
public static string DoEncrypt(string unencryptedString)
{
string encryptedString = "";
unencryptedString = new string(unencryptedString.ToCharArray().Reverse().ToArray());
foreach (char character in unencryptedString.ToCharArray())
{
string randomizationSeed = (encryptedString.Length > 0) ? unencryptedString.Substring(0, encryptedString.Length) : "";
encryptedString += GetRandomSubstitutionArray(randomizationSeed)[int.Parse(character.ToString())];
}
return Shuffle(encryptedString);
}
public static string DoDecrypt(string encryptedString)
{
// Unshuffle the string first to make processing easier.
encryptedString = Unshuffle(encryptedString);
string unencryptedString = "";
foreach (char character in encryptedString.ToCharArray().ToArray())
unencryptedString += GetRandomSubstitutionArray(unencryptedString).IndexOf(int.Parse(character.ToString()));
// Reverse string since encrypted string was reversed while processing.
return new string(unencryptedString.ToCharArray().Reverse().ToArray());
}
private static string Shuffle(string unshuffled)
{
char[] unshuffledCharacters = unshuffled.ToCharArray();
char[] shuffledCharacters = new char[12];
shuffledCharacters[0] = unshuffledCharacters[2];
shuffledCharacters[1] = unshuffledCharacters[7];
shuffledCharacters[2] = unshuffledCharacters[10];
shuffledCharacters[3] = unshuffledCharacters[5];
shuffledCharacters[4] = unshuffledCharacters[3];
shuffledCharacters[5] = unshuffledCharacters[1];
shuffledCharacters[6] = unshuffledCharacters[0];
shuffledCharacters[7] = unshuffledCharacters[4];
shuffledCharacters[8] = unshuffledCharacters[8];
shuffledCharacters[9] = unshuffledCharacters[11];
shuffledCharacters[10] = unshuffledCharacters[6];
shuffledCharacters[11] = unshuffledCharacters[9];
return new string(shuffledCharacters);
}
private static string Unshuffle(string shuffled)
{
char[] shuffledCharacters = shuffled.ToCharArray();
char[] unshuffledCharacters = new char[12];
unshuffledCharacters[0] = shuffledCharacters[6];
unshuffledCharacters[1] = shuffledCharacters[5];
unshuffledCharacters[2] = shuffledCharacters[0];
unshuffledCharacters[3] = shuffledCharacters[4];
unshuffledCharacters[4] = shuffledCharacters[7];
unshuffledCharacters[5] = shuffledCharacters[3];
unshuffledCharacters[6] = shuffledCharacters[10];
unshuffledCharacters[7] = shuffledCharacters[1];
unshuffledCharacters[8] = shuffledCharacters[8];
unshuffledCharacters[9] = shuffledCharacters[11];
unshuffledCharacters[10] = shuffledCharacters[2];
unshuffledCharacters[11] = shuffledCharacters[9];
return new string(unshuffledCharacters);
}
public static string DoPrefixCipherEncrypt(string strIn, byte[] btKey)
{
if (strIn.Length < 1)
return strIn;
// Convert the input string to a byte array
byte[] btToEncrypt = System.Text.Encoding.Unicode.GetBytes(strIn);
RijndaelManaged cryptoRijndael = new RijndaelManaged();
cryptoRijndael.Mode =
CipherMode.ECB;//Doesn't require Initialization Vector
cryptoRijndael.Padding =
PaddingMode.PKCS7;
// Create a key (No IV needed because we are using ECB mode)
ASCIIEncoding textConverter = new ASCIIEncoding();
// Get an encryptor
ICryptoTransform ictEncryptor = cryptoRijndael.CreateEncryptor(btKey, null);
// Encrypt the data...
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, ictEncryptor, CryptoStreamMode.Write);
// Write all data to the crypto stream to encrypt it
csEncrypt.Write(btToEncrypt, 0, btToEncrypt.Length);
csEncrypt.Close();
//flush, close, dispose
// Get the encrypted array of bytes
byte[] btEncrypted = msEncrypt.ToArray();
// Convert the resulting encrypted byte array to string for return
return (Convert.ToBase64String(btEncrypted));
}
private static List<int> GetRandomSubstitutionArray(string number)
{
// Pad number as needed to achieve longer key length and seed more randomly.
// NOTE I didn't want to make the code here available and it would take too longer to clean, so I'll tell you what I did. I basically took every number seed that was passed in and prefixed it and postfixed it with some values to make it 16 characters long and to get a more unique result. For example:
// if (number.Length = 15)
// number = "Y" + number;
// if (number.Length = 14)
// number = "7" + number + "z";
// etc - hey I already said this is a hack ;)
// We pass in the current number as the password to an AES encryption of each of the
// digits 0 - 9. This returns us a set of values that we can then sort and get a
// random order for the digits based on the current state of the number.
Dictionary<string, int> prefixCipherResults = new Dictionary<string, int>();
for (int ndx = 0; ndx < 10; ndx++)
prefixCipherResults.Add(DoPrefixCipherEncrypt(ndx.ToString(), Encoding.UTF8.GetBytes(number)), ndx);
// Order the results and loop through to build your int array.
List<int> group = new List<int>();
foreach (string key in prefixCipherResults.Keys.OrderBy(k => k))
group.Add(prefixCipherResults[key]);
return group;
}
One more way for simple encryption, you can just substruct each number from 10.
For example
initial numbers: 123456
10-1 = 9
10-2 = 8
10-3 = 7
etc.
and you will get
987654
You can combine it with XOR for more secure encryption.
What you're talking about is kinda like a one-time pad. A key the same length as the plaintext and then doing some modulo math on each individual character.
A xor B = C
C xor B = A
or in other words
A xor B xor B = A
As long as you don't use the same key B on multiple different inputs (e.g. B has to be unique, every single time you encrypt), then in theory you can never recover the original A without knowing what B was. If you use the same B multiple times, then all bets are off.
comment followup:
You shouldn't end up with more bits aftewards than you started with. xor just flips bits, it doesn't have any carry functionality. Ending up with 6 digits is just odd... As for code:
$plaintext = array(digit1, digit2, digit3, digit4, digit5, digit6);
$key = array(key1, key2, key3, key4, key5, key6);
$ciphertext = array()
# encryption
foreach($plaintext as $idx => $char) {
$ciphertext[$idx] = $char xor $key[$idx];
}
# decryption
foreach($ciphertext as $idx => $char) {
$decrypted[$idx] = $char xor $key[$idx];
}
Just doing this as an array for simplicity. For actual data you'd work on a per-byte or per-word basis, and just xor each chunk in sequence. You can use a key string shorter than the input, but that makes it easier to reverse engineer the key. In theory, you could use a single byte to do the xor'ing, but then you've just basically achieved the bit-level equivalent of rot-13.
For example you can add digits of your number with digits some const (214354178963...whatever) and apply "~" operator (reverse all bits) this is not safely but ensure you can decrypt your number allways.
anyone with reflector or ildasm will be able to hack such an encryption algorithm.
I don't know what is your business requirement but you have to know that.
If there's enough wriggle-room in the requirements that you can accept 16 hexadecimal digits as the encrypted side, just interpret the 12 digit decimal number as a 64bit plaintext and use a 64 bit block cipher like Blowfish, Triple-DES or IDEA.

C# Create an Auth Token from Guid combined with 40Char Hex string (UUID)

I am writing an asp.net MVC app that drives an IPhone application.
I want the Iphone to send me its UUID looks like this:
2b6f0cc904d137be2e1730235f5664094b831186
On the server I want to generate a Guid:
466853EB-157D-4795-B4D4-32658D85A0E0
On both the Iphone and the Server I need a simple aglorithm to combine these 2 values into an Auth token that can be passed around. Both the IPhone and the ASP.NET MVC app need to be able to compute the value over and over based on the UUID and the GUID.
So this needs to be a simple algorithm with no libraries from the .net framework.
Full Solution Here
public void Test()
{
var DeviceId = Guid.NewGuid();
var newId = "2b6f0cc904d137be2e1730235f5664094b831186";
var guidBytes = DeviceId.ToByteArray();
var iphoneBytes = StringToByteArray(newId);
byte[] xor = new byte[guidBytes.Length];
for (int i=0;i<guidBytes.Length;i++)
{
xor[i] = (byte) (guidBytes[i] ^ iphoneBytes[i]);
}
var result = ByteArrayToString(xor);
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
Well, the iPhone ID looks like a hex string, so converting both to binary and XORing the bytes ought to do it. You could store the result as an array, hex string, or base-64 encoded string as appropriate.
The way you refer to this as an "auth token" is a little concerning, however. Session ids must be unpredictable. You might consider generating an array of cryptographically random data on the server instead of a GUID.
Edit
// Convert the server GUID to a byte array.
byte[] guidBytes = severGuid.ToByteArray();
// Convert the iPhone device ID to an array
byte[] idBytes = StringToByteArray(iPhoneId);
Sadly, it seems .NET doesn't have a built-in method to convert to/from hex strings, but this subject has been covered before: Convert byte array to hex string and vice versa
// Once you've XORed the bytes, conver the result to a string.
string outputString = ByteArrayToString(outputBytes);
Just as a side note, all the "auth token" mechanisms I've worked with (at least) concatenated a constant value (a "secret") with the current time, then hashed them together then sent the hash and the date. The server then reconstructed the hash from the received date and known "secret" and then compared to the received hash (signature).
My point here was "concatenated with date" - this allows the resulting signature to be different every time which in theory should be more secure.
Rather than XORing, which loses information, you could just concatenate these hex digits.
Why do you even need the GUID? The phone ID is unique, the GUID seems to add no value.
I thought you can use two way algorithm. It mean the algorithm can be encode and decode like Base64, SHA256, AES

Categories