1

Can c# donet generate same UUID for following java code? if so how? i tried GUID but didn't work!

Text:

String cleartext = "CN=CompanyName;mac=some mac;@host=somehost;email=admin@somedomain.com;issued=01/01/20013;expire=12/12/2013";

Java code:

UUID uuid = UUID.nameUUIDFromBytes(cleartext.getBytes("UTF-8"));

C# code:

byte[] b = System.Text.Encoding.UTF8.GetBytes(cleartext);
        Guid uid = new Guid(b);
        Console.Write(uid.ToString());

REF Earlier discussions

Community
  • 1
  • 1
gpa
  • 2,411
  • 6
  • 38
  • 68

3 Answers3

12

If all you need is the same UUID string (and not actual UUID/Guid objects), this C# method will return the same value as Java's UUID.nameUUIDFromBytes(byte[]) method.

public static string NameUUIDFromBytes(byte[] input)
{
    MD5 md5 = MD5.Create();
    byte[] hash = md5.ComputeHash(input);
    hash[6] &= 0x0f;
    hash[6] |= 0x30;
    hash[8] &= 0x3f;
    hash[8] |= 0x80;
    string hex = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
    return hex.Insert(8, "-").Insert(13, "-").Insert(18, "-").Insert(23, "-");
}

C# Example

string test = "test";
Console.Out.WriteLine(NameUUIDFromBytes(Encoding.UTF8.GetBytes(test)));

Output:
098f6bcd-4621-3373-8ade-4e832627b4f6

Java Example

UUID test = UUID.nameUUIDFromBytes("test".getBytes("UTF-8"));
System.out.println(test);

Output:
098f6bcd-4621-3373-8ade-4e832627b4f6

Edit: I know it's after the fact, but this will produce an actual Guid object with the same value. Just incase anyone wants it.

public static Guid NameGuidFromBytes(byte[] input)
{
    MD5 md5 = MD5.Create();
    byte[] hash = md5.ComputeHash(input);
    hash[6] &= 0x0f;
    hash[6] |= 0x30;
    hash[8] &= 0x3f;
    hash[8] |= 0x80;

    byte temp = hash[6];
    hash[6] = hash[7];
    hash[7] = temp;

    temp = hash[4];
    hash[4] = hash[5];
    hash[5] = temp;

    temp = hash[0];
    hash[0] = hash[3];
    hash[3] = temp;

    temp = hash[1];
    hash[1] = hash[2];
    hash[2] = temp;
    return new Guid(hash);
}
Syon
  • 7,205
  • 5
  • 36
  • 40
  • Nice! `+1` for putting this together. – Mike Christensen Aug 02 '13 at 18:05
  • Was looking at what Guid produced and I noticed that the difference was just that some of the bytes were swapped. So I've added a method for creating an actual Guid as well, just if anyone needs it. – Syon Aug 02 '13 at 18:24
  • Is there anyway to get back original input text with this MD5? i guess not huh? – gpa Aug 02 '13 at 20:22
  • No, MD5 is a one way hashing algorithm. Reversing it is not possible. – Syon Aug 02 '13 at 20:57
1

This code is definitely not going to work with .NET.

The Guid(Byte[]) constructor must take in 16 bytes (as Guids are 128 bits), otherwise it will throw an ArgumentException. Your string is much more than 16 bytes.

However, with that said, C# and Java will still not produce the same UUIDs using the same 16 bytes passed into the constructor. In Java, you can pass in any arbitrary number of bytes into the UUID constructor and it will create a hash of those bytes. In other words:

In C#:

Guid g = new Guid(new Byte[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16});
Console.WriteLine(g);

Will produce a different value than:

UUID u = UUID.nameUUIDFromBytes(new byte[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16});
System.out.println(u);

...in Java.

You could probably implement .NET's Byte[16] constructor in Java, or implement Java's hash constructor in .NET, but I would suggest using a string representation of your UUID across both platforms, for example, "190c4c10-5786-3212-9d85-018939108a6c".

If you're trying to create a hash from a string, you might want to check into the MD5 class. You'd want something like:

var md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(cleartext);
byte[] hashBytes  = md5.ComputeHash(inputBytes);

MD5 is a standard algorithm and will produce the same hash for the same string in both .NET and Java.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • That Java factory method takes a byte string, MD5 hashes it, runs it through a mangler, and then sets the appropriate flags to label it as a name-based UUID. See section 14 of [the UUID doc](http://www.itu.int/rec/T-REC-X.667-200409-S/en) for the algorithm. – chrylis -cautiouslyoptimistic- Aug 02 '13 at 16:40
  • @chrylis - Are you saying Java's `UUID(byte[])` constructor and .NET's `GUID(byte[])` constructor will produce different UUIDs for the same 16 bytes? If that's the case, this person might be best off representing the UUID with a string. – Mike Christensen Aug 02 '13 at 16:45
  • No, Java has no `UUID(byte[])` constructor. I understand .NET's `(byte[])` constructor to "reconstitute" an existing UUID from its byte representation (basically wrapping the byte array); the [corresponding Java constructor](http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html#UUID(long,%20long)) takes two `long`s. `nameUUIDFromBytes` follows the algorithm in section 14 to turn an arbitrary string (such as a DN) into a UUID with the flags set to indicate "this UUID was generated from a name". – chrylis -cautiouslyoptimistic- Aug 02 '13 at 16:49
0

If you want interoperability don't depend on code that's not under your control. It could change with each Java version or implementation.

You could take the way that is used

/**
 * Static factory to retrieve a type 3 (name based) {@code UUID} based on
 * the specified byte array.
 *
 * @param  name
 *         A byte array to be used to construct a {@code UUID}
 *
 * @return  A {@code UUID} generated from the specified array
 */
public static UUID nameUUIDFromBytes(byte[] name) {
    MessageDigest md;
    try {
        md = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException nsae) {
        throw new InternalError("MD5 not supported");
    }
    byte[] md5Bytes = md.digest(name);
    md5Bytes[6]  &= 0x0f;  /* clear version        */
    md5Bytes[6]  |= 0x30;  /* set to version 3     */
    md5Bytes[8]  &= 0x3f;  /* clear variant        */
    md5Bytes[8]  |= 0x80;  /* set to IETF variant  */
    return new UUID(md5Bytes);
}

source

and copy it into your code. Create exactly that in other languages as well and your problem should be gone.

In case "type 3 (name based) UUID" is a standard where the result is exactly specified, you could skip copying it in Java since implementation should never return a different result. It's likely that you will find implementations for other languages as well and don't need to port it by hand.

zapl
  • 63,179
  • 10
  • 123
  • 154
  • 2
    The implementation of name-based UUID generation is an implementation of a specification down to individual bits; it's not going to change with the whims of the platform vendor any more than the implementation of MD5 is. – chrylis -cautiouslyoptimistic- Aug 02 '13 at 16:50
  • Good to know, a "type 3" UUID could mean a lot of things and I was not sure what exactly. For example having just those few bits set in a specific way. – zapl Aug 02 '13 at 16:53