Here's how to compress and decompress Packed GUIDs or some people refer to them as Compressed GUIDs in C-Sharp
Input GUID {12345678-ABCD-EFAB-1234-ABCDEFABCDEF}
Packed GUID is 87654321DCBABAFE2143BADCFEBADCFE
A Packed GUID format is loosely defined as having a length of 32 characters, where the GUID is rearranged and the braces '{' and dashes '-' are removed.
Note: A "Compressed GUID" is a intermediate format, that rearranges the GUID and is Base85 encoded (using a restricted set) and has a length of 21 characters long and used to create Darwin Descriptors.
A Darwin Descriptor is an encoded string and when decoded produces a combination of the ProductCode, Feature & ComponentId(s) and generally used for Windows installer, because it provides feature resilience through a mechanism called COM Advertising.
Here's an example of a Darwin Descriptor, which you may have though was a virus entry in your registry!
"w_1^VX!!!!!!!!!MKKSkEXCELFiles>tW{~$4Q]c@II=l2xaTO5Z"
decoded yields a GUID, feature name, and a GUID.
{91120000-0030-0000-0000-0000000ff1ce}EXCELFiles{0638c49d-bb8b-4cd1-b191-052e8f325736}
See my post for C# code to convert a GUID to a Darwin Descriptor
To decode Darwin Descriptors that are in the registry, use RegtoText tool to decode all values en masse (free demo available).
In example code below, I use "compressed GUID" to describe Packed GUID.
using System; using System.Collections.Generic; // public class Program { public static bool IsHex(IEnumerable<char> chars) { bool isHex; foreach(var c in chars) { isHex = ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); if(!isHex) return false; } return true; } public static void Main() { //Source - http://www.hanselman.com/blog/BATCHFILEVOODOODetermineIfMultipleAndWhichVersionsOfAnMSIinstalledProductAreInstalledUsingUpgradeCode.aspx //like to but to bulky - https://docs.microsoft.com/en-us/dotnet/standard/base-types/how-to-define-and-use-custom-numeric-format-providers //https://installpac.wordpress.com/2008/03/31/packed-guids-darwin-descriptors-and-windows-installer-reference-counting/ //PROTO //{12345678-ABCD-WXYZ-1234-ABCDEFGHIJKL} //should be-> 87654321DCBAZYXW2134BADCFEHGJILK //string inStrGUID = "{12345678-ABCD-WXYZ-1234-ABCDEFGHIJKL}"; //cannot use this contrived GUID has hex values above > (A-F) string inStrGUID = "{12345678-ABCD-EFAB-1234-ABCDEFABCDEF}"; string expectedCompressedGUID = "87654321DCBABAFE2143BADCFEBADCFE"; //https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse?view=netframework-4.7.2 - N has no dashes string outputFormat = "N"; //outputFormat can be N, D, B, P - N has no dashes string outCompressedGuid = ""; string outDecompressedGuid = ""; Guid inGuid = new Guid(); Guid outGuid = new Guid(); Guid outDCGuid = new Guid(); bool isValidGuid = Guid.TryParse(inStrGUID, out inGuid); Console.WriteLine("Input GUID " + inStrGUID+ " is valid? "+isValidGuid); if (isValidGuid) { string raw = inGuid.ToString("N"); //N for no dashes char[] aRaw = raw.ToCharArray(); //compressed format reverses 11 byte sequences of the original guid int[] revs = new int[]{8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2}; int pos = 0; for (int i = 0; i < revs.Length; i++) { Array.Reverse(aRaw, pos, revs[i]); pos += revs[i]; } string newstrGuid = new string(aRaw); bool isoutValidGuid = Guid.TryParse(newstrGuid, out outGuid); if ( isoutValidGuid ) { //GUID in registry are all caps. outCompressedGuid = outGuid.ToString(outputFormat).ToUpper(); Console.WriteLine("out CGUID "+ outGuid.ToString("B").ToUpper()+" before full compression (removal of dashes) here for readability"); //for readability Console.WriteLine("\nCompressed guid is "+ outCompressedGuid ); if (outCompressedGuid == expectedCompressedGUID) Console.WriteLine("Matched expectations."); else Console.WriteLine("Did not met expectations."); } else Console.WriteLine("Failed to compress GUID."); } Console.WriteLine("\nInput Compressed GUID " + outCompressedGuid); char[] chrArrCGUID = outCompressedGuid.ToCharArray(); //Here's a typical GUID Compressed in a Registry Key //what if ? S-1-5-21-xxxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxx - split on new char[] {' ','-'} check any that are length 32 //Expand/Decompress/Decrypt Compressed GUID if (outCompressedGuid.Length == 32 && Program.IsHex(chrArrCGUID)==true){ //validate potential Compressed GUID int[] reversalidxs= new int[]{8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2}; int pos = 0; for (int i = 0; i < reversalidxs.Length; i++) { Array.Reverse(chrArrCGUID, pos, reversalidxs[i]); pos += reversalidxs[i]; } string newstrGuid = new string(chrArrCGUID); bool isoutValidDCGuid = Guid.TryParse(newstrGuid, out outDCGuid ); if ( isoutValidDCGuid ) { //GUID in registry are all caps. outDecompressedGuid = outDCGuid.ToString("B").ToUpper(); //Console.WriteLine("\nInput Compressed GUID "+ outDCGuid.ToString("B").ToUpper()+" this line for comparison only"); //for readability Console.WriteLine("Output Decomprsd GUID "+ outDCGuid.ToString("N").ToUpper()+" this line for comparison only"); //for readability Console.WriteLine("\nDecompressed compressed guid is "+ outDecompressedGuid ); } } else Console.WriteLine("Failed to decompressed CGUID."); } }
var ng = Guid.NewGuid();
ReplyDeletevar uncompressedLength = ng.ToString().Length; // Uncompressed 36;
var compressedLength = ng.ToString("N").Length; // length 32
var compressedStringGuid = ng.ToString("N"); // Compressed Guid
Helpful snippets, thanks.
ReplyDelete