I have a 3rd party application that I can't control that uses Java's UUID.nameUUIDFromBytes
to create a string. I need to reproduce this function written in JS.
In OpenJDK's source I found this:
public static UUID nameUUIDFromBytes(byte[] name) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("MD5 not supported", nsae);
}
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);
}
For the life of me I can't figure it out, mostly because of how JS abstracts bytes.
TL;DR: I just need a js function that will produce the same string as UUID.nameUUIDFromBytes((VARIABLE).getBytes(Charsets.UTF_8)).toString()
.
I have a 3rd party application that I can't control that uses Java's UUID.nameUUIDFromBytes
to create a string. I need to reproduce this function written in JS.
In OpenJDK's source I found this:
public static UUID nameUUIDFromBytes(byte[] name) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("MD5 not supported", nsae);
}
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);
}
For the life of me I can't figure it out, mostly because of how JS abstracts bytes.
TL;DR: I just need a js function that will produce the same string as UUID.nameUUIDFromBytes((VARIABLE).getBytes(Charsets.UTF_8)).toString()
.
3 Answers
Reset to default 5Okay so, this is not pure-js, but it is nodejs.
const crypto = require('crypto');
function javaHash(input) {
let md5Bytes = crypto.createHash('md5').update(input).digest();
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 md5Bytes.toString('hex');
}
This solution gave me exact UUID for me
const crypto = require('crypto');
const hexToUuid = require('hex-to-uuid');
const javaHash = (input) => {
var md5Bytes = crypto.createHash('md5').update(input).digest()
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 hexToUuid(md5Bytes.toString('hex'))
}
console.log('javaHash', javaHash("HelloWorld"));
// 68e109f0-f40c-372a-95e0-5cc22786f8e6
This answer attempts to improve on the previous ones as follows
- It includes the hyphens in the output, just like Java
- Does not rely on additional external libraries that are not supported anymore
const crypto = require('crypto');
function javaHash(input:string) {
let md5Bytes = crypto.createHash('md5').update(input).digest();
md5Bytes[6] &= 0x0f; /* clear version */
md5Bytes[6] |= 0x30; /* set to version 3 */
md5Bytes[8] &= 0x3f; /* clear variant */
md5Bytes[8] |= 0x80; /* set to IETF variant */
const hex = md5Bytes.toString('hex')
const uuid = hex.replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, "$1-$2-$3-$4-$5");
return uuid;
}
It relies on the UUID spec being exactly 128bits in length