1

I'm trying to convert this code (from David Clunie) to C#, for the purposes of creating OIDs from UUID (or GUID) in my program

public static String createOIDFromUUIDCanonicalHexString(String hexString) throws IllegalArgumentException {
        UUID uuid = UUID.fromString(hexString);
        long leastSignificantBits = uuid.getLeastSignificantBits();
        long mostSignificantBits  = uuid.getMostSignificantBits();
        BigInteger decimalValue = makeBigIntegerFromUnsignedLong(mostSignificantBits);
        decimalValue = decimalValue.shiftLeft(64);
        BigInteger bigValueOfLeastSignificantBits = makeBigIntegerFromUnsignedLong(leastSignificantBits);
        decimalValue = decimalValue.or(bigValueOfLeastSignificantBits);   // not add() ... do not want to introduce question of signedness of long
        return OID_PREFIX+"."+decimalValue.toString();

I don't understand why make the longs (leastSignificantBits, mostSignificantBits) from the parts of the UUID, and then make the bigint from them - why not just directly make a BigInt? (since he's shifting the most significant digits left anyway).

Can anyone give me any insight into why this is written the way it is? (disclaimer: I have not tried to run the java code, I'm just trying to implement this in C#)

[EDIT]

Turns out there were several problems - a big one, as Kevin Coulombe points out, is the byte order Microsoft stores GUIDs in. The java code seems to get the bytes in the obvious (left to right) order, but in two separate chunks, apparently (also thanks to Kevin) because there's no easy way to get the whole byte array in Java.

Here is working C# code, forwards and (partially) backwards:

    class Program
{
    const string OidPrefix = "2.25.";

    static void Main(string[] args)
    {
        Guid guid = new Guid("000000FF-0000-0000-0000-000000000000");
        //Guid guid = new Guid("f81d4fae-7dec-11d0-a765-00a0c91e6bf6");
        Console.WriteLine("Original guid: " + guid.ToString());
        byte[] guidBytes = StringToByteArray(guid.ToString().Replace("-", ""));
        BigInteger decimalValue = new BigInteger(guidBytes);
        Console.WriteLine("The OID is " + OidPrefix + decimalValue.ToString());
        string hexGuid = decimalValue.ToHexString().PadLeft(32, '0');//padded for later use
        Console.WriteLine("The hex value of the big int is " + hexGuid);
        Guid testGuid = new Guid(hexGuid);
        Console.WriteLine("This guid should match the orginal one: " + testGuid);
        Console.ReadKey();
    }

    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;
    }
}
Aerik
  • 2,307
  • 1
  • 27
  • 39

2 Answers2

1

I think they do it this way because there is no easy way of converting the UUID to a byte array to pass to the BigInteger in Java.

See this : GUID to ByteArray

In C#, this should be what you are looking for :

String oid = "prefix" + "." + new System.Numerics.BigInteger(
        System.Guid.NewGuid().ToByteArray()).ToString();
Community
  • 1
  • 1
Kevin Coulombe
  • 1,517
  • 1
  • 17
  • 35
  • Hmm... maybe, but that yields a different result than the example given with the java code... I think there's a difference in how java's getLeastSignificantBits / getMostSignificantBits works compared to a GUID's ToByteArray method. For example, (new Guid("000000FF-0000-0000-0000-000000000000")).ToByteArray() gives me {255,0,0,0,0,0,0...} but if I put the FF in the first position, I get {0,0,0,FF,0,0...} – Aerik Jul 25 '13 at 23:23
  • I didn't know about this, but the way a GUID and a UUID are stored is not necessarily the same. They are stored by parts, but the endianness of these parts seems to be subject to interpretation : http://stackoverflow.com/questions/10190817/guid-byte-order-in-net – Kevin Coulombe Jul 25 '13 at 23:44
  • 2
    Here it is directly from the microsoft references : "Note that the order of bytes in the returned byte array is different from the string representation of a Guid value. The order of the beginning four-byte group and the next two two-byte groups is reversed, whereas the order of the last two-byte group and the closing six-byte group is the same." http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx – Kevin Coulombe Jul 25 '13 at 23:50
  • 1
    @KevinCoulombe - thanks, that's what I'm finding. If I take the string representation of the GUID and manually parse it (taking pairs of hex characters) into a byte array, then pass that into a BigInt, I get the same result as the Java example. – Aerik Jul 25 '13 at 23:51
0
String oid_prefix = "2.25"
String hexString = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
UUID uuid = UUID.fromString(hexString);
long leastSignificantBits = uuid.getLeastSignificantBits();
long mostSignificantBits  = uuid.getMostSignificantBits();
mostSignificantBits = mostSignificantBits & Long.MAX_VALUE;
BigInteger decimalValue = BigInteger.valueOf(mostSignificantBits);
decimalValue = decimalValue.setBit(63);
decimalValue = decimalValue.shiftLeft(64);
leastSignificantBits = leastSignificantBits & Long.MAX_VALUE;
BigInteger bigValueLeastSignificantBit = BigInteger.valueOf(leastSignificantBits);
bigValueLeastSignificantBit = bigValueLeastSignificantBit.setBit(63);
decimalValue = decimalValue.or(bigValueLeastSignificantBit);
println "oid is = "+oid_prefix+"."+decimalValue
TryinHard
  • 4,078
  • 3
  • 28
  • 54