Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UUID v3 Support #217

Merged
merged 8 commits into from
Sep 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion README_js.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS.

Features:

* Support for version 1, 4 and 5 UUIDs
* Support for version 1, 3, 4 and 5 UUIDs
* Cross-platform
* Uses cryptographically-strong random number APIs (when available)
* Zero-dependency, small footprint (... but not [this small](https://gist.github.com/982883))
Expand All @@ -28,6 +28,25 @@ const uuidv1 = require('uuid/v1');
uuidv1(); // RESULT
```

Version 3 (namespace):

```javascript --context
const uuidv3 = require('uuid/v3');

// ... using predefined DNS namespace (for domain names)
uuidv3('hello.example.com', uuidv3.DNS); // RESULT

// ... using predefined URL namespace (for, well, URLs)
uuidv3('http://example.com/hello', uuidv3.URL); // RESULT

// ... using a custom namespace
//
// Note: Custom namespaces should be a UUID string specific to your application!
// E.g. the one here was generated using this modules `uuid` CLI.
const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
uuidv3('Hello, World!', MY_NAMESPACE); // RESULT
```

Version 4 (random):

```javascript --context
Expand Down Expand Up @@ -67,6 +86,15 @@ uuidv1(); // -> v1 UUID
</script>
```

For version 3 uuids:

```html
<script src="http://wzrd.in/standalone/uuid%2Fv3@latest"></script>
<script>
uuidv3('http://example.com/hello', uuidv3.URL); // -> v3 UUID
</script>
```

For version 4 uuids:

```html
Expand Down Expand Up @@ -135,6 +163,40 @@ uuidv1(null, arr, 0); // RESULT
uuidv1(null, arr, 16); // RESULT
```

### Version 3

```javascript
const uuidv3 = require('uuid/v3');

// Incantations
uuidv3(name, namespace);
uuidv3(name, namespace, buffer);
uuidv3(name, namespace, buffer, offset);
```

Generate and return a RFC4122 v3 UUID.

* `name` - (String | Array[]) "name" to create UUID with
* `namespace` - (String | Array[]) "namespace" UUID either as a String or Array[16] of byte values
* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.
* `offset` - (Number) Starting index in `buffer` at which to begin writing. Default = 0

Returns `buffer`, if specified, otherwise the string form of the UUID

Example:

```javascript --run
// Generate a unique namespace (typically you would do this once, outside of
// your project, then bake this value into your code)
const uuidv4 = require('uuid/v4');
const uuidv3 = require('uuid/v3');
const MY_NAMESPACE = uuidv4(); // RESULT

// Generate a couple namespace uuids
uuidv3('hello', MY_NAMESPACE); // RESULT
uuidv3('world', MY_NAMESPACE); // RESULT
```

### Version 4

```javascript
Expand Down
15 changes: 15 additions & 0 deletions bin/uuid
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ function usage() {
console.log('Usage:');
console.log(' uuid');
console.log(' uuid v1');
console.log(' uuid v3 <name> <namespace uuid>');
console.log(' uuid v4');
console.log(' uuid v5 <name> <namespace uuid>');
console.log(' uuid --help');
Expand All @@ -25,6 +26,20 @@ switch (version) {
console.log(uuidV1());
break;

case 'v3':
var uuidV3 = require('../v3');

var name = args.shift();
var namespace = args.shift();
assert(name != null, 'v3 name not specified');
assert(namespace != null, 'v3 namespace not specified');

if (namespace == 'URL') namespace = uuidV3.URL;
if (namespace == 'DNS') namespace = uuidV3.DNS;

console.log(uuidV3(name, namespace));
break;

case 'v4':
var uuidV4 = require('../v4');
console.log(uuidV4());
Expand Down
218 changes: 218 additions & 0 deletions lib/md5-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Browser-compatible JavaScript MD5
*
* Modification of JavaScript MD5
* https://github.com/blueimp/JavaScript-MD5
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*
* Based on
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/

'use strict;'

function md5(bytes) {

if (typeof(bytes) == 'string') {
var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
bytes = new Array(msg.length);
for (var i = 0; i < msg.length; i++) bytes[i] = msg.charCodeAt(i);
}

return md5ToHexEncodedArray(
wordsToMd5(
bytesToWords(bytes)
, bytes.length * 8)
)
}


/*
* Convert an array of little-endian words to an array of bytes
*/
function md5ToHexEncodedArray(input) {
var i
var x
var output = []
var length32 = input.length * 32
var hexTab = '0123456789abcdef'
var hex

for (i = 0; i < length32; i += 8) {
x = (input[i >> 5] >>> (i % 32)) & 0xFF

hex = parseInt(hexTab.charAt((x >>> 4) & 0x0F) + hexTab.charAt(x & 0x0F), 16)

output.push(hex)
}
return output
}

/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function wordsToMd5 (x, len) {
/* append padding */
x[len >> 5] |= 0x80 << (len % 32)
x[(((len + 64) >>> 9) << 4) + 14] = len

var i
var olda
var oldb
var oldc
var oldd
var a = 1732584193
var b = -271733879
var c = -1732584194

var d = 271733878

for (i = 0; i < x.length; i += 16) {
olda = a
oldb = b
oldc = c
oldd = d

a = md5ff(a, b, c, d, x[i], 7, -680876936)
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)

a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
b = md5gg(b, c, d, a, x[i], 20, -373897302)
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473)
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)

a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
d = md5hh(d, a, b, c, x[i], 11, -358537222)
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)

a = md5ii(a, b, c, d, x[i], 6, -198630844)
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)

a = safeAdd(a, olda)
b = safeAdd(b, oldb)
c = safeAdd(c, oldc)
d = safeAdd(d, oldd)
}
return [a, b, c, d]
}

/*
* Convert an array bytes to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function bytesToWords(input) {

var i
var output = []
output[(input.length >> 2) - 1] = undefined
for (i = 0; i < output.length; i += 1) {
output[i] = 0
}
var length8 = input.length * 8
for (i = 0; i < length8; i += 8) {
output[i >> 5] |= (input[(i / 8)] & 0xFF) << (i % 32)
}

return output
}

/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safeAdd (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF)
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
return (msw << 16) | (lsw & 0xFFFF)
}

/*
* Bitwise rotate a 32-bit number to the left.
*/
function bitRotateLeft (num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}

/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5cmn (q, a, b, x, s, t) {
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
}
function md5ff (a, b, c, d, x, s, t) {
return md5cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function md5gg (a, b, c, d, x, s, t) {
return md5cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function md5hh (a, b, c, d, x, s, t) {
return md5cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5ii (a, b, c, d, x, s, t) {
return md5cmn(c ^ (b | (~d)), a, b, x, s, t)
}

module.exports = md5;
21 changes: 21 additions & 0 deletions lib/md5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

var crypto = require('crypto');

function md5(bytes) {
// support modern Buffer API
if (typeof Buffer.from === 'function') {
if (Array.isArray(bytes)) bytes = Buffer.from(bytes);
else if (typeof bytes === 'string') bytes = Buffer.from(bytes, 'utf8');
}

// support pre-v4 Buffer API
else {
if (Array.isArray(bytes)) bytes = new Buffer(bytes);
else if (typeof bytes === 'string') bytes = new Buffer(bytes, 'utf8');
}

return crypto.createHash('md5').update(bytes).digest();
}

module.exports = md5;
Loading