/*
Copyright 2008-2011 Clipperz Srl
This file is part of Clipperz's Javascript Crypto Library.
Javascript Crypto Library provides web developers with an extensive
and efficient set of cryptographic functions. The library aims to
obtain maximum execution speed while preserving modularity and
reusability.
For further information about its features and functionalities please
refer to http://www.clipperz.com
* Javascript Crypto Library is free software: you can redistribute
it and/or modify it under the terms of the GNU Affero General Public
License as published by the Free Software Foundation, either version
3 of the License, or (at your option) any later version.
* Javascript Crypto Library is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
License along with Javascript Crypto Library. If not, see
.
*/
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
//=============================================================================
Clipperz.ByteArray_abstract = function(args) {
return this;
}
Clipperz.ByteArray_abstract.prototype = MochiKit.Base.update(null, {
//-------------------------------------------------------------------------
'toString': function() {
return "Clipperz.ByteArray_abstract";
},
//-------------------------------------------------------------------------
'equals': function(aValue) {
return (this.compare(aValue) == 0);
},
//-------------------------------------------------------------------------
'compare': function(aValue) {
var result;
var i;
result = MochiKit.Base.compare(this.length(), aValue.length());
i = this.length();
while ((result == 0) && (i>0)) {
i--;
result = MochiKit.Base.compare(this.byteAtIndex(i), aValue.byteAtIndex(i));
}
return result;
},
//-------------------------------------------------------------------------
'clone': function() {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
'newInstance': function() {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
'reset': function() {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
'length': function() {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
'checkValue': function(aValue) {
if ((aValue & 0xff) != aValue) {
MochiKit.Logging.logError("Clipperz.ByteArray.appendByte: the provided value (0x" + aValue.toString(16) + ") is not a byte value.");
throw Clipperz.ByteArray.exception.InvalidValue;
}
},
//-------------------------------------------------------------------------
'xorMergeWithBlock': function(aBlock, anAllignment, paddingMode) {
var result;
var a, b;
var aLength;
var bLength;
var i, c;
if (this.length() > aBlock.length()) {
a = this;
b = aBlock;
} else {
a = aBlock;
b = this;
}
aLength = a.length();
bLength = b.length();
if (aLength != bLength) {
if (paddingMode == 'truncate') {
if (anAllignment == 'left') {
a = a.split(0, bLength);
} else {
a = a.split(aLength - bLength);
}
} else {
var ii, cc;
var padding;
// padding = new Clipperz.ByteArray();
padding = this.newInstance();
cc = aLength - bLength;
for (ii=0; ii> 8) & 0xff, (aValue >> 16) & 0xff, (aValue >> 24) & 0xff ); // little endian
} else {
result = this.appendBytes( (aValue >> 24) & 0xff, (aValue >> 16) & 0xff, (aValue >> 8) & 0xff, (aValue) & 0xff ); // big endian - DEFAULT
}
return result;
},
'appendWords': function(args) {
var values;
var i,c;
if (args.constructor == Array) {
values = args;
} else {
values = arguments;
}
c = values.length;
for (i=0; i 0) {
selectedByteMask = (1 << bitPositionInSelectedByte);
} else {
selectedByteMask = 1;
}
result = selectedByte & selectedByteMask ? 1 : 0;
//console.log("aBitPosition: " + aBitPosition + ", length: " + this.length() + ", bytePosition: " + bytePosition + ", bitPositionInSelectedByte: " + bitPositionInSelectedByte + ", selectedByteMask: " + selectedByteMask);
return result;
},
//-------------------------------------------------------------------------
'bitBlockAtIndexWithSize': function(aBitPosition, aSize) {
var result;
var bitValue;
var i,c;
result = 0;
c = aSize;
for (i=0; i> 4);
if (value3 != -1) {
byte2 = ((value2 & 0x0f) << 4) | ((value3 & 0x3c) >> 2);
if (value4 != -1) {
byte3 = ((value3 & 0x03) << 6) | (value4);
} else {
byte3 = null;
}
} else {
byte2 = null;
byte3 = null;
}
this.appendByte(byte1);
this.appendByte(byte2);
this.appendByte(byte3);
i += 4;
}
return this;
},
//-------------------------------------------------------------------------
'toBase64String': function() {
var result;
var length;
var i;
var byte1, byte2, byte3;
var char1, char2, char3, char4;
i = 0;
length = this.length();
result = new Array(Math.ceil(length/3));
while (i < length) {
byte1 = this.byteAtIndex(i);
if ((i+2) < length) {
byte2 = this.byteAtIndex(i+1);
byte3 = this.byteAtIndex(i+2);
} else if ((i+2) == length) {
byte2 = this.byteAtIndex(i+1);
byte3 = null;
} else {
byte2 = null;
byte3 = null;
}
char1 = this.base64mapIndex[byte1 >> 2];
if (byte2 != null) {
char2 = this.base64mapIndex[((byte1 & 0x03) << 4) | ((byte2 & 0xf0) >> 4)];
if (byte3 != null) {
char3 = this.base64mapIndex[((byte2 & 0x0f) << 2) | ((byte3 & 0xc0) >> 6)];
char4 = this.base64mapIndex[(byte3 & 0x3f)];
} else {
char3 = this.base64mapIndex[(byte2 & 0x0f) << 2];
char4 = "=";
}
} else {
char2 = this.base64mapIndex[(byte1 & 0x03) << 4];
char3 = "=";
char4 = "=";
}
result.push(char1 + char2 + char3 + char4);
i += 3;
}
return result.join("");
},
//-------------------------------------------------------------------------
'base32map': "0123456789abcdefghjkmnpqrstvwxyz",
'base32mapIndex': "0123456789abcdefghjkmnpqrstvwxyz".split(''),
//-------------------------------------------------------------------------
'appendBase32String': function(aValue) {
var value;
var i;
var length;
var value1, value2, value3, value4, value5, value6, value7, value8;
var byte1, byte2, byte3, byte4, byte5;
value = aValue.toLowerCase();
value = value.replace(/[\s\-]/g, '');
value = value.replace(/[0o]/g, '0');
value = value.replace(/[1il]/g, '1');
length = value.length;
if ((length % 8) != 0) {
MochiKit.Logging.logError("the value passed to the 'ByteArray.setBase32Value' is not correct");
throw Clipperz.ByteArray.exception.InvalidValue;
}
i = 0;
while (i> 2);
if (value3 != -1) {
byte2 = ((value2 & 0x03) << 6) | (value3 << 1) | ((value4 & 0x10) >> 4);
if (value5 != -1) {
byte3 = ((value4 & 0x0f) << 4) | ((value5 & 0x1e) >> 1);
if (value6 != -1) {
byte4 = ((value5 & 0x01) << 7) | (value6 << 2) | ((value7 & 0x18) >> 3);
if (value8 != -1) {
byte5 = ((value7 & 0x07) << 5) | (value8);
}
}
}
}
this.appendByte(byte1);
this.appendByte(byte2);
this.appendByte(byte3);
this.appendByte(byte4);
this.appendByte(byte5);
i += 8;
}
return this;
},
//-------------------------------------------------------------------------
'toBase32String': function() {
var result;
var length;
var i;
var byte1, byte2, byte3, byte4, byte5;
var char1, char2, char3, char4, char5, char6, char7, char8;
i = 0;
length = this.length();
result = new Array(Math.ceil(length/5));
while (i < length) {
byte1 = this.byteAtIndex(i);
if ((i+4) < length) {
byte2 = this.byteAtIndex(i+1);
byte3 = this.byteAtIndex(i+2);
byte4 = this.byteAtIndex(i+3);
byte5 = this.byteAtIndex(i+4);
} else if ((i+4) == length) {
byte2 = this.byteAtIndex(i+1);
byte3 = this.byteAtIndex(i+2);
byte4 = this.byteAtIndex(i+3);
byte5 = null;
} else if ((i+3) == length) {
byte2 = this.byteAtIndex(i+1);
byte3 = this.byteAtIndex(i+2);
byte4 = null;
byte5 = null;
} else if ((i+2) == length) {
byte2 = this.byteAtIndex(i+1);
byte3 = null;
byte4 = null;
byte5 = null;
} else {
byte2 = null;
byte3 = null;
byte4 = null;
byte5 = null;
}
char1 = this.base32mapIndex[byte1 >> 3];
char2 = char3 = char4 = char5 = char6 = char7 = char8 = "=";
if (byte2 != null) {
char2 = this.base32mapIndex[((byte1 & 0x07) << 2) | ((byte2 & 0xc0) >> 6)];
char3 = this.base32mapIndex[((byte2 & 0x3e) >> 1)];
if (byte3 != null) {
char4 = this.base32mapIndex[((byte2 & 0x01) << 4) | ((byte3 & 0xf0) >> 4)];
if (byte4 != null) {
char5 = this.base32mapIndex[((byte3 & 0x0f) << 1) | ((byte4 & 0x80) >> 7)];
char6 = this.base32mapIndex[(byte4 & 0x7c) >> 2];
if (byte5 != null) {
char7 = this.base32mapIndex[((byte4 & 0x03) << 3) | ((byte5 & 0xe0) >> 5)];
char8 = this.base32mapIndex[(byte5 & 0x1f)];
} else {
char7 = this.base32mapIndex[(byte4 & 0x03) << 3];
}
} else {
char5 = this.base32mapIndex[(byte3 & 0x0f) << 1];
}
} else {
char4 = this.base32mapIndex[(byte2 & 0x01) << 4];
}
} else {
char2 = this.base32mapIndex[(byte1 & 0x07) << 2];
}
result.push(char1 + char2 + char3 + char4 + char5 + char6 + char7 + char8);
i += 5;
}
return result.join("");
},
//-------------------------------------------------------------------------
'split': function(aStartingIndex, anEndingIndex) {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
'increment': function() {
var i;
var done;
done = false;
i = this.length() - 1;
while ((i>=0) && (done == false)) {
var currentByteValue;
currentByteValue = this.byteAtIndex(i);
if (currentByteValue == 0xff) {
this.setByteAtIndex(0, i);
if (i>= 0) {
i --;
} else {
done = true;
}
} else {
this.setByteAtIndex(currentByteValue + 1, i);
done = true;
}
}
},
//-------------------------------------------------------------------------
'arrayValues': function() {
throw Clipperz.Base.exception.AbstractMethod;
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//=============================================================================
//
// Clipperz.ByteArray_hex
//
//=============================================================================
Clipperz.ByteArray_hex = function (args) {
this._value = "";
if (typeof(args) != 'undefined') {
if (args.constructor == Array) {
this.appendBytes(args);
} else if (args.constructor == String) {
if (args.indexOf("0x") == 0) {
var value;
value = args.substring(2).toLowerCase();
if (/[0123456789abcdef]*/.test(value)) {
if ((value.length % 2) == 0) {
this._value = value;
} else {
this._value = "0" + value;
}
} else {
MochiKit.Logging.logError("Clipperz.ByteArray should be inizialized with an hex string.");
throw Clipperz.ByteArray.exception.InvalidValue;
}
} else {
var value;
var i,c;
c = args.length;
value = new Array(c);
for (i=0; i 0xxxxxxx
result.push(unicode);
// } else if ((unicode >= 0x80) && (unicode <= 0x7ff)) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
} else if (unicode <= 0x7ff) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
result.push((unicode >> 6) | 0xc0);
result.push((unicode & 0x3F) | 0x80);
// } else if ((unicode >= 0x0800) && (unicode <= 0xffff)) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
} else if (unicode <= 0xffff) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
result.push((unicode >> 12) | 0xe0);
result.push(((unicode >> 6) & 0x3f) | 0x80);
result.push((unicode & 0x3f) | 0x80);
} else { // 0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result.push((unicode >> 18) | 0xf0);
result.push(((unicode >> 12) & 0x3f) | 0x80);
result.push(((unicode >> 6) & 0x3f) | 0x80);
result.push((unicode & 0x3f) | 0x80);
}
}
}
this._value = result;
} else {
this._value = [];
this.appendBytes(MochiKit.Base.extend(null, arguments));
}
} else {
this._value = [];
}
return this;
}
Clipperz.ByteArray_array.prototype = MochiKit.Base.update(new Clipperz.ByteArray_abstract(), {
//-------------------------------------------------------------------------
'toString': function() {
return "Clipperz.ByteArray_array";
},
//-------------------------------------------------------------------------
'clone': function() {
var result;
result = this.newInstance();
result.appendBytes(this._value);
return result;
},
//-------------------------------------------------------------------------
'newInstance': function() {
return new Clipperz.ByteArray_array();
},
//-------------------------------------------------------------------------
'reset': function() {
this._value = [];
},
//-------------------------------------------------------------------------
'length': function() {
return (this._value.length);
},
//-------------------------------------------------------------------------
'appendBlock': function(aBlock) {
MochiKit.Base.extend(this._value, aBlock._value);
return this;
},
//-------------------------------------------------------------------------
'appendByte': function(aValue) {
if (aValue != null) {
this.checkValue(aValue);
this._value.push(aValue);
}
return this;
},
//-------------------------------------------------------------------------
'byteAtIndex': function(anIndex) {
return this._value[anIndex];
},
'setByteAtIndex': function(aValue, anIndex) {
var missingBytes;
this.checkValue(aValue);
missingBytes = anIndex - this.length();
if (missingBytes < 0) {
this._value[anIndex] = aValue;
} else if (missingBytes == 0) {
this._value.push(aValue);
} else {
var i,c;
c = missingBytes;
for (i=0; i 0xxxxxxx
result = self.byteToHex(aUnicode);
// } else if ((aUnicode >= 0x80) && (aUnicode <= 0x7ff)) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
} else if (aUnicode <= 0x7ff) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
result = self.byteToHex((aUnicode >> 6) | 0xc0);
result += self.byteToHex((aUnicode & 0x3F) | 0x80);
// } else if ((aUnicode >= 0x0800) && (aUnicode <= 0xffff)) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
} else if (aUnicode <= 0xffff) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
result = self.byteToHex((aUnicode >> 12) | 0xe0);
result += self.byteToHex(((aUnicode >> 6) & 0x3f) | 0x80);
result += self.byteToHex((aUnicode & 0x3f) | 0x80);
} else { // 0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result = self.byteToHex((aUnicode >> 18) | 0xf0);
result += self.byteToHex(((aUnicode >> 12) & 0x3f) | 0x80);
result += self.byteToHex(((aUnicode >> 6) & 0x3f) | 0x80);
result += self.byteToHex((aUnicode & 0x3f) | 0x80);
}
return result;
}
Clipperz.ByteArray.pushUtf8BytesOfUnicodeChar = function(anArray, aUnicode) {
var self;
self = Clipperz.ByteArray;
if (aUnicode <= 0x7f) { // 0x00000000 - 0x0000007f -> 0xxxxxxx
anArray.push(aUnicode);
// } else if ((aUnicode >= 0x80) && (aUnicode <= 0x7ff)) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
} else if (aUnicode <= 0x7ff) { // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
anArray.push((aUnicode >> 6) | 0xc0);
anArray.push((aUnicode & 0x3F) | 0x80);
// } else if ((aUnicode >= 0x0800) && (aUnicode <= 0xffff)) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
} else if (aUnicode <= 0xffff) { // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
anArray.push((aUnicode >> 12) | 0xe0);
anArray.push(((aUnicode >> 6) & 0x3f) | 0x80);
anArray.push((aUnicode & 0x3f) | 0x80);
} else { // 0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
anArray.push((aUnicode >> 18) | 0xf0);
anArray.push(((aUnicode >> 12) & 0x3f) | 0x80);
anArray.push(((aUnicode >> 6) & 0x3f) | 0x80);
anArray.push((aUnicode & 0x3f) | 0x80);
}
}
Clipperz.ByteArray.exception = {
InvalidValue: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue")
};
//#############################################################################
Clipperz.ByteArrayIterator = function(args) {
args = args || {};
this._byteArray = args.byteArray;
this._blockSize = args.blockSize;
this._finalPadding = args.finalPadding || false;
this._currentPosition = 0;
return this;
}
Clipperz.ByteArrayIterator.prototype = MochiKit.Base.update(null, {
//-------------------------------------------------------------------------
'toString': function() {
return "Clipperz.ByteArrayIterator";
},
//-------------------------------------------------------------------------
'blockSize': function() {
var result;
result = this._blockSize;
return result;
},
//-------------------------------------------------------------------------
'currentPosition': function() {
var result;
result = this._currentPosition;
return result;
},
//-------------------------------------------------------------------------
'byteArray': function() {
var result;
result = this._byteArray;
return result;
},
//-------------------------------------------------------------------------
'finalPadding': function() {
var result;
result = this._finalPadding;
return result;
},
//-------------------------------------------------------------------------
'nextBlock': function() {
var result;
var currentPosition;
var byteArrayLength;
currentPosition = this._currentPosition;
byteArrayLength = this.byteArray().length();
if (currentPosition < byteArrayLength) {
var i,c;
c = this.blockSize();
result = new Array(c);
for (i=0; i