Skip to content

Commit

Permalink
sha-1 and uuid implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
TitanNano committed Sep 9, 2016
1 parent 4059a28 commit c79684d
Show file tree
Hide file tree
Showing 2 changed files with 362 additions and 0 deletions.
198 changes: 198 additions & 0 deletions modules/sha-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@

/**
* casts any number to an unsigned 32-bit integer
*
* @param {number} value any numeric value
*
* @return {number} an int32 number
*/
let uint32 = function(value) {
//cast to integer
value = value | 0;

//make value unsigned
value = value >>> 0;

//limit to 32 bit
value = value % Math.pow(2, 32);

return value;
}

/**
* rotates the bits of an uint32 value to the left.
*
* @param {number} value should be uint to prevent unwanted side effects
* @param {number} amount the amount of bits to shift <= 32
*
* @return {number} the rotated value already casted to uint32
*/
let leftRotateBits = function(value, amount) {
value = (value << amount) | (value >>> 32 - amount);
value = uint32(value);

return value;
}

/**
* makes sure a hex value is 32-bit long.
*
* @param {string} value a hex string
*
* @return {string} a hex string which is definetely 32-bit long
*/
let hex32Bit = function(value) {
while (value.length * 4 < 32) {
value = '0' + value;
}

return value;
}

/**
* makes sure a hex value is 32-bit long.
*
* @param {string} value a hex string
*
* @return {string} a hex string which is definetely 32-bit long
*/
let hex64Bit = function(value) {
while (value.length * 4 < 64) {
value = '0' + value;
}

return value;
}

/**
* creates a new array buffer from the utf-8 encoded string.
*
* @param {string} value the original value
*
* @return {ArrayBuffer} the encoded value
*/
let stringToBuffer = function(value) {
// make sure every character is only 8 bit long
value = unescape(encodeURIComponent(value));

let bufferView = new Uint8Array(value.length);

// push message into buffer
for (let i = 0; i < value.length; i++) {
bufferView[i] = value.charCodeAt(i);
}

return bufferView.buffer;
}

/**
* the sha-1 algorithm.
*
* @param {(ArrayBuffer|string)} message the message to hash
*
* @return {string} the hex representation of the hash value
*/
let sha1 = function(message) {

if (typeof message === 'string') {
message = stringToBuffer(message);
}

// initial values
let h0 = 0x67452301;
let h1 = 0xEFCDAB89;
let h2 = 0x98BADCFE;
let h3 = 0x10325476;
let h4 = 0xC3D2E1F0;

let messageLength = message.byteLength;
let bufferSize = 0;
let buffer = null;
let view = null;

// calculate buffer size. First in bit and then convert to byte.
bufferSize = (messageLength + 1) * 8;
bufferSize = bufferSize + (448 - (bufferSize % 512)) + 64;
bufferSize = bufferSize / 8;
buffer = new ArrayBuffer(bufferSize);
view = new Uint8Array(buffer);

//apply data to our local buffer
view.set(new Uint8Array(message), 0);

// append the 1 bit. No idea why this is not just a single bit.
view[messageLength] = 0x80;


//reorder bytes
for(let i = 0; i < messageLength + 1; i+= 4) {
let temp = 0;

temp = view[i];
view[i] = view[i+3];
view[i+3] = temp;

temp = view[i+1];
view[i+1] = view[i+2];
view[i+2] = temp;
}

//append the message length
view = new Uint32Array(buffer);
let length = hex64Bit((messageLength * 8).toString(16));
view[view.length - 2] = parseInt(length.substring(0, length.length - 8), 16);
view[view.length - 1] = parseInt(length.substring(length.length - 8), 16);

// process each chunk
for (let i = 0; i < bufferSize / (512 / 8); i++) {
let a = h0;
let b = h1;
let c = h2;
let d = h3;
let e = h4;
let temp = 0;

view = new Uint32Array(80);
view.set(new Uint32Array(buffer.slice(i * 512, (i + 1 ) * 512)), 0);

for (let i = 16; i < 80; i++) {
view[i] = leftRotateBits(view[i - 3] ^ view[i - 8] ^ view[i - 14] ^ view[i - 16], 1);
}

for (let i = 0; i < 80; i++) {
let f = null;
let k = null;

if (i > -1 && i < 20) {
f = uint32((b & c) ^ (~b & d))
k = 0x5A827999;
} else if (i > 19 && i < 40) {
f = uint32(b ^ c ^ d);
k = 0x6ED9EBA1;
} else if (i > 39 && i < 60) {
f = uint32((b & c) ^ (b & d) ^ (c & d));
k = 0x8F1BBCDC;
} else if (i > 59 && i < 80) {
f = uint32(b ^ c ^ d);
k = 0xCA62C1D6;
}

temp = uint32(leftRotateBits(a, 5) + f + e + k + view[i]);
e = uint32(d);
d = uint32(c);
c = leftRotateBits(b, 30);
b = uint32(a)
a = uint32(temp);
}

h0 = uint32(h0 + a);
h1 = uint32(h1 + b);
h2 = uint32(h2 + c);
h3 = uint32(h3 + d);
h4 = uint32(h4 + e);
}

return hex32Bit(h0.toString(16)) + hex32Bit(h1.toString(16)) + hex32Bit(h2.toString(16)) + hex32Bit(h3.toString(16)) + hex32Bit(h4.toString(16));
}

export default sha1;
164 changes: 164 additions & 0 deletions modules/uuid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { Make } from '../util/make.js';
import sha1 from './sha-1.js';

/**
* @module Uuid
*/

const UUID_SIZE = 16; // 16 byte / 128 bit

/** @lends module:Uuid~ReadBytesOfHexString# */
let ReadBytesOfHexString = {

/**
* the remaining hex string data
*
* @type {string}
*/
_value: null,

/**
* [_make description]
*
* @constructs
*
* @param {string} value a hex string
*
* @return {void}
*/
_make: function(value) {
this._value = value;
},

/**
* reads the lowest byte from the hex string, expecting bigendian notation.
*
* @return {number} uint8
*/
readByte: function() {
let byte = parseInt(this._value.substring(this._value.length - 2), 16);
this._value = this._value.substring(0, this._value.length - 2);

return byte >>> 0;
}
}

let hex8Bit = function(value) {
while(value.length * 4 < 8) {
value = '0' + value;
}

return value;
}

let hex16Bit = function(value) {
while(value.length * 4 < 16) {
value = '0' + value;
}

return value;
}

let hex32Bit = function(value) {
while(value.length * 4 < 32) {
value = '0' + value;
}

return value;
}

let hex48Bit = function(value) {
while(value.length * 4 < 32) {
value = '0' + value;
}

return value;
}


export let parse = function(uuid) {
let index = 0;
let buffer = new Uint8Array(UUID_SIZE);
let [time_low, time_mid, time_hi_and_version, clock_seq, node] = uuid.split('-');

let pushToBuffer = function(byte) {
buffer[index++] = parseInt(byte, 16);
}

hex32Bit(time_low || '').match(/.{1,2}/g).reverse().forEach(pushToBuffer);
hex16Bit(time_mid || '').match(/.{1,2}/g).reverse().forEach(pushToBuffer);
hex16Bit(time_hi_and_version || '').match(/.{1,2}/g).reverse().forEach(pushToBuffer);
hex16Bit(clock_seq || '').match(/.{1,2}/g).reverse().forEach(pushToBuffer);
hex48Bit(node || '').match(/.{1,2}/g).reverse().forEach(pushToBuffer);

return buffer.buffer;
}

/**
* [v5 description]
*
* @param {string} namespace the name space of the new uuid
* @param {string} name the name of the resource of this uuid
*
* @return {string} uuid string
*/
export let v5 = function(namespace, name) {
let nameValue = new ArrayBuffer(name.length);
let namespaceValue = parse(namespace);
let completeValue = new Uint8Array(nameValue.byteLength + namespaceValue.byteLength);
let uuidBuffer = new Uint8Array(UUID_SIZE);
let view = null;
let hash = null;

view = new Uint8Array(nameValue);

for (let i = 0; i < name.length; i++) {
view[i] = name.charCodeAt(i);
}

completeValue.set(new Uint8Array(namespaceValue), 0);
completeValue.set(new Uint8Array(nameValue), namespaceValue.byteLength);

hash = sha1(completeValue.buffer);
hash = Make(ReadBytesOfHexString)(hash);

//time_low (0 - 3)
for (let i = 0; i < 4; i++) {
uuidBuffer[i] = hash.readByte();
}

// time_mid (4 - 5)
for (let i = 4; i < 6; i++) {
uuidBuffer[i] = hash.readByte();
}

// time_hi_and_version (6 - 7)
for (let i = 6; i < 8; i++) {
uuidBuffer[i] = hash.readByte();
}

uuidBuffer[7] = (uuidBuffer[7] & 0x0F) | 0x50;

// clock_seq_hi_and_reserved (8)
uuidBuffer[8] = (hash.readByte() & 0x3F) | 0x80;

// clock_seq_low (9)
uuidBuffer[9] = hash.readByte();

// node (10 - 15)
for (let i = 10; i < 16; i++) {
uuidBuffer[i] = hash.readByte();
}

let time_low = hex8Bit(uuidBuffer[3].toString(16)) + hex8Bit(uuidBuffer[2].toString(16)) +
hex8Bit(uuidBuffer[1].toString(16)) + hex8Bit(uuidBuffer[0].toString(16));
let time_mid = hex8Bit(uuidBuffer[5].toString(16)) + hex8Bit(uuidBuffer[4].toString(16));
let time_hi_and_version = hex8Bit(uuidBuffer[7].toString(16)) + hex8Bit(uuidBuffer[6].toString(16));
let clock_seq_hi_and_reserved = hex8Bit(uuidBuffer[8].toString(16));
let clock_seq_low = hex8Bit(uuidBuffer[9].toString(16));
let node = hex8Bit(uuidBuffer[15].toString(16)) + hex8Bit(uuidBuffer[14].toString(16)) +
hex8Bit(uuidBuffer[13].toString(16)) + hex8Bit(uuidBuffer[12].toString(16)) +
hex8Bit(uuidBuffer[11].toString(16)) + hex8Bit(uuidBuffer[10].toString(16));

return `${time_low}-${time_mid}-${time_hi_and_version}-${clock_seq_hi_and_reserved}${clock_seq_low}-${node}`;
}

0 comments on commit c79684d

Please sign in to comment.