PDA

View Full Version : Ext.ux.Crypto



JeffHowden
26 Aug 2007, 12:30 PM
I just finished up the final touches on the port of two encryption algorithms (AES (http://ext.vosandhowden.com/ux/crypto/aes.cfm) and TEA (http://ext.vosandhowden.com/ux/crypto/tea.cfm)) and one hashing algorithm (SHA-1 (http://ext.vosandhowden.com/ux/crypto/sha1.cfm)). Check them: http://extjs.com/learn/Extension:Crypto

trbs
26 Aug 2007, 3:12 PM
very cool, thanks jeff !

franklt69
26 Aug 2007, 4:26 PM
Hi Jeff or other, to learn could you write in an application when could be useful to use Extension:Crypto ?

regards
Frank

JeffHowden
26 Aug 2007, 8:18 PM
http://www.devarticles.com/c/a/JavaScript/Building-a-CHAP-Login-System-Coding-ServerSide-Random-Seeds/

galdaka
26 Aug 2007, 11:40 PM
Your live examples not work for me. IE6. I can

JeffHowden
27 Aug 2007, 7:58 AM
Indeed, something is amiss in IE6. I'll look into it.

JeffHowden
27 Aug 2007, 8:28 AM
Well, I've fiddled with the examples, but can't figure out why none of them show any fields in IE6. I'm swamped with stuff today, so not sure if I'll be able to get to it. If anybody has any clues, I'd really appreciate it.

unixmast
29 Dec 2007, 5:25 AM
.

vtswingkid
4 Feb 2008, 5:40 AM
The links to your js files are broken. Path is "crypto" not "cryto".

Thanks for the algorithms

JeffHowden
4 Feb 2008, 1:29 PM
Fixed, thanks.

vtswingkid
6 Feb 2008, 11:56 AM
I have encrypted and decrypted fine in javascript...

Do you know what openssl method I can use to encrypt decrypt that will be compatible?

openssl enc -aes-256-cbc ?

vtswingkid
11 Feb 2008, 5:10 AM
I took the nist documents and implemented the foward and reverse cipher. Then I wrapped those with both the cbc and ecb algorithms. I'll submit them soon. I still would like to figure out how openssl generates the key and iv from a standard text password. But in the mean time the key and iv (in the case of cbc) can be passed in.

For simplicity I'll just post it under and aes extension. You could add it to crypto if you like it though.

vtswingkid
12 Feb 2008, 3:37 PM
I have written a new AES extension for crypto. It is compatible with openssl.

I do not yet support salts, and I am using sha1 digest for the key and iv creation...

examples:

echo -n "test" | openssl enc -aes256 -a -md sha1 -pass pass:testpass

feed that output to AES

Ext.ux.Crypto.AES.Decrypt({pass:"testpass", data:output, b64:true});

similarly...

var out2=Ext.ux.Crypto.AES.Encrypt({pass:"testpass2", data:"test2", b64:true, mode:"ecb", bits:192});

decrypt out2 with openssl

echo -n out2 | openssl enc -d -eas-192-ecb -a -md sha1 -pass pass:testpass2

options for Decrypt and Encrypt include:
pass: ascii password string
data: ascii string, byte array
b64: true/false (default false)
mode: "ecb"/"cbc" (default "cbc")
bits: 128/192/256 (default 256)
key: byte array of length 16/24/32 (generated if pass is provided)
iv: byte array of length 16 (generated if pass is provided)

I also provided access to all of the base routines that Encrypt and Decrypt make use of incase you want to by pass some things.

Here is the code.


//ADVANCED ENCRYPTION STANDARD (AES)
//
//VERSION: 1.0.1
//AUTHOR: Robert Williams (Extjs User: vtswingkid)
//
//SUMMARY: This version of AES is based NIST's Processing Standards Publication 197.
// ECB and CBC modes haven been implemented with compatibility to that of openssl.

Ext.namespace('Ext.ux', 'Ext.ux.Crypto');

Ext.ux.Crypto.AES = function(){
//Number of columns (32-bit words) comprising the State. For this
//standard, Nb = 4.
var Nb=4;

//The round constant word array.
var Rcon = [
[0x00, 0x00, 0x00, 0x00],
[0x01, 0x00, 0x00, 0x00],
[0x02, 0x00, 0x00, 0x00],
[0x04, 0x00, 0x00, 0x00],
[0x08, 0x00, 0x00, 0x00],
[0x10, 0x00, 0x00, 0x00],
[0x20, 0x00, 0x00, 0x00],
[0x40, 0x00, 0x00, 0x00],
[0x80, 0x00, 0x00, 0x00],
[0x1b, 0x00, 0x00, 0x00],
[0x36, 0x00, 0x00, 0x00]
];

//Non-linear substitution table used in several byte substitution
//transformations and in the Key Expansion routine to perform a onefor-
//one substitution of a byte value.
var Sbox = [
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
];

//Inverse of Sbox
var InvSbox = [
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
];

var B64Map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
var B64Pad="=";
var InvB64Map = new Array();
for(var i=0;i<B64Map.length;i++)InvB64Map[B64Map[i]]=i;
//Function used in the Key Expansion routine that takes a four-byte
//input word and applies an S-box to each of the four bytes to
//produce an output word.
var SubWord = function(word){
for(var i=0;i<4;i++)word[i]= Sbox[word[i]];
return word;
};

//Function used in the Key Expansion routine that takes a four-byte
//word and performs a cyclic permutation.
var RotWord = function(word){
temp=word[0];
for(var i=0;i<3;i++)word[i]= word[i+1];
word[3]=temp;
return word;
};

//Transformation in the Cipher and Inverse Cipher in which a Round
//Key is added to the State using an XOR operation. The length of a
//Round Key equals the size of the State (i.e., for Nb = 4, the Round
//Key length equals 128 bits/16 bytes).
var AddRoundKey = function(state, round, roundKeys){
var row, col;
for (row=0; row<4; row++) {
for (col=0; col<Nb; col++) state[row][col] ^= roundKeys[round*4+col][row];
}
return state;
};

//Transformation in the Cipher that processes the State using a nonlinear
//byte substitution table (S-box) that operates on each of the
//State bytes independently.
var SubBytes = function(state){
var row,col;
var tmp;
for(row=0; row<4; row++){
for(col=0; col<Nb; col++){
tmp=state[row][col];
state[row][col]=Sbox[state[row][col]];
}
}
return state;
};

//Transformation in the Cipher that processes the State by cyclically
//shifting the last three rows of the State by different offsets.
var ShiftRows = function(state){
var row,col;
var tmp = new Array();
for(row=1; row<4; row++){
for(col=0; col<Nb; col++)tmp[col]=state[row][(col+row)%Nb];
for(col=0; col<Nb; col++)state[row][col]=tmp[col];
}
return state;
};

//Transformation in the Cipher that takes all of the columns of the
//State and mixes their data (independently of one another) to
//produce new columns.
var MixColumns = function(state){
var col, i;
var x1 = new Array(); // times 1
var x2 = new Array(); // times 2
var x3 = new Array(); // times 3
for (col=0; col<Nb; col++) {
for (i=0; i<4; i++) {
x1[i] = state[i][col]; //{01}*Sx
x2[i] = x1[i]<<1; //{02}*Sx
if(x2[i]>0xff)x2[i]^=0x011b;
x3[i] = x1[i] ^ x2[i]; //{03}*Sx
}
//state[0] = ({02}*S0) ^ ({03}*S1) ^ S2 ^ S3
state[0][col] = x2[0] ^ x3[1] ^ x1[2] ^ x1[3];
//state[1] = S0 ^ ({02}*S1) ^ ({03}*S2) ^ S3
state[1][col] = x1[0] ^ x2[1] ^ x3[2] ^ x1[3];
//state[2] = S0 ^ S1 ^ ({02}*S2) ^ ({03}*S3)
state[2][col] = x1[0] ^ x1[1] ^ x2[2] ^ x3[3];
//state[3] = ({03}*S0) ^ S1 ^ S2 ^ ({02}*S3)
state[3][col] = x3[0] ^ x1[1] ^ x1[2] ^ x2[3];
}
return state;
};

//Transformation in the Inverse Cipher that is the inverse of
//SubBytes().
var InvSubBytes = function(state){
var row,col;
var tmp;
for(row=0; row<4; row++){
for(col=0; col<Nb; col++){
tmp=state[row][col];
state[row][col]=InvSbox[state[row][col]];
}
}
return state;
};

//Transformation in the Inverse Cipher that is the inverse of
//ShiftRows().
var InvShiftRows = function(state){
var row,col;
var tmp = new Array();
for(row=1; row<4; row++){
for(col=0; col<Nb; col++)tmp[col]=state[row][(col+(Nb-row))%Nb];
for(col=0; col<Nb; col++)state[row][col]=tmp[col];
}
return state;
};

//Transformation in the Inverse Cipher that is the inverse of
//MixColumns().
var InvMixColumns = function(state){
var col, i;
var x1 = new Array(); // times 0x01
var x2 = new Array(); // times 0x02
var x4 = new Array(); // times 0x04
var x8 = new Array(); // times 0x08
var x9 = new Array(); // times 0x09
var xB = new Array(); // times 0x0b
var xD = new Array(); // times 0x0d
var xE = new Array(); // times 0x0e
for (col=0; col<Nb; col++) {
for (i=0; i<4; i++) {
x1[i] = state[i][col]; //{01}*Sx
x2[i] = x1[i]<<1; //{02}*Sx
if(x2[i]>0xff)x2[i]^=0x011b;
x4[i] = x2[i]<<1; //{04}*Sx
if(x4[i]>0xff)x4[i]^=0x011b;
x8[i] = x4[i]<<1; //{08}*Sx
if(x8[i]>0xff)x8[i]^=0x011b;
x9[i] = x8[i] ^ x1[i]; //{09}*Sx
xB[i] = x8[i] ^ x2[i] ^ x1[i]; //{0b}*Sx
xD[i] = x8[i] ^ x4[i] ^ x1[i]; //{0d}*Sx
xE[i] = x8[i] ^ x4[i] ^ x2[i]; //{0e}*Sx
}
//state[0] = ({0e}*S0) ^ ({0b}*S1) ^ ({0d}*S2) ^ ({09}*S3)
state[0][col] = xE[0] ^ xB[1] ^ xD[2] ^ x9[3];
//state[1] = ({09}*S0) ^ ({0e}*S1) ^ ({0b}*S2) ^ ({0d}*S3)
state[1][col] = x9[0] ^ xE[1] ^ xB[2] ^ xD[3];
//state[2] = ({0d}*S0) ^ ({09}*S1) ^ ({0e}*S2) ^ ({0b}*S3)
state[2][col] = xD[0] ^ x9[1] ^ xE[2] ^ xB[3];
//state[3] = ({0b}*S0) ^ ({0d}*S1) ^ ({09}*S2) ^ ({0e}*S3)
state[3][col] = xB[0] ^ xD[1] ^ x9[2] ^ xE[3];
}
return state;
};

return{
KeyExpansion:function(key){
var i,j;
var temp = new Array();
var Nk; //Number of 32-bit words comprising the Cipher Key. For this
//standard, Nk = 4, 6, or 8.
var Nr; //Number of rounds, which is a function of Nk and Nb (which is
//fixed). For this standard, Nr = 10, 12, or 14.
if(!(key instanceof Array && (key.length==16 || key.length==24 || key.length==32))){
alert("KeyExpansion: key must be an array of length 16, 24, or 32 bytes");
}
Nk=key.length/4;
Nr=Nk+6;
roundKeys=new Array();

for(i=0;i<Nk;i++){
roundKeys[i]=[key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
}

for(;i<Nb*(Nr+1);i++){
roundKeys[i]=new Array();
for (j = 0; j < 4; j++)temp[j] = roundKeys[i - 1][j];
if (i % Nk == 0) {
temp = SubWord(RotWord(temp));
for (j = 0; j < 4; j++)temp[j] ^= Rcon[i/Nk][j];
}else if (Nk>6 && i%Nk==4){
temp = SubWord(temp);
}
for (j=0; j<4; j++) roundKeys[i][j] = roundKeys[i-Nk][j] ^ temp[j];
}

return roundKeys
},

Cipher: function(input, roundKeys){
var row,col;
var Nr; //Number of rounds, which is a function of Nk and Nb (which is
//fixed). For this standard, Nr = 10, 12, or 14.
var state=new Array(); //Intermediate Cipher result that can be pictured as a rectangular array
//of bytes, having four rows and Nb columns.
var output=new Array();
var round;

if(!(input instanceof Array && input.length==4*Nb)){
alert("Cipher: input must be an array of length "+(4*Nb));
return null;
}
if(!(roundKeys instanceof Array && (roundKeys.length==Nb*11 || roundKeys.length==Nb*13 || roundKeys.length==Nb*15))){
alert("Cipher: roundKeys must be an array of length "+(Nb*11)+", "+(Nb*13)+", or "+(Nb*15));
return null;
}
Nr = roundKeys.length/Nb - 1;

//copy the input to the state
for(row=0; row<4; row++){
state[row]=new Array();
for(col=0; col<Nb; col++){
state[row][col]=input[row+4*col];
}
}
//PrintState(state, "copy");

//cipher
state=AddRoundKey(state, 0, roundKeys);

for(round=1; round<Nr; round++){
state=SubBytes(state);
state=ShiftRows(state);
state=MixColumns(state);
state=AddRoundKey(state, round, roundKeys);
}

state=SubBytes(state);
state=ShiftRows(state);
state=AddRoundKey(state, Nr, roundKeys);
//PrintState(state, "final");

//copy state to output
for(row=0; row<4; row++){
for(col=0; col<Nb; col++){
output[row+4*col]=state[row][col];
}
}

return output;
},

InvCipher: function(input, roundKeys){
var row,col;
var Nr; //Number of rounds, which is a function of Nk and Nb (which is
//fixed). For this standard, Nr = 10, 12, or 14.
var state=new Array(); //Intermediate Cipher result that can be pictured as a rectangular array
//of bytes, having four rows and Nb columns.
var output=new Array();
var round;

if(!(input instanceof Array && input.length==4*Nb)){
alert("Cipher: input must be an array of length "+(4*Nb));
return null;
}
if(!(roundKeys instanceof Array && (roundKeys.length==Nb*11 || roundKeys.length==Nb*13 || roundKeys.length==Nb*15))){
alert("Cipher: roundKeys must be an array of length "+(Nb*11)+", "+(Nb*13)+", or "+(Nb*15));
return null;
}
Nr = roundKeys.length/Nb - 1;

//copy the input to the state
for(row=0; row<4; row++){
state[row]=new Array();
for(col=0; col<Nb; col++){
state[row][col]=input[row+4*col];
}
}
//PrintState(state, "copy");

//cipher
state=AddRoundKey(state, Nr, roundKeys);

for(round=Nr-1; round>0; round--){
state=InvShiftRows(state);
state=InvSubBytes(state);
state=AddRoundKey(state, round, roundKeys);
state=InvMixColumns(state);
}

state=InvShiftRows(state);
state=InvSubBytes(state);
state=AddRoundKey(state, 0, roundKeys);
//PrintState(state, "final");

//copy state to output
for(row=0; row<4; row++){
for(col=0; col<Nb; col++){
output[row+4*col]=state[row][col];
}
}

return output;
},

StringToKeyIv: function(str, bits){
var h;
var hash = new Array();
var key = new Array();
var iv = new Array();
var nkey=0;
var niv=16;
var i;
if(bits!=128 && bits!=192 && bits!=256){
alert("BytesToKey: bits must be 128, 192, or 256");
return null;
}
nkey=bits/8;
h=Ext.ux.Crypto.SHA1.hash(str).toString();
for(i=0;i<h.length;i+=2)hash[i/2]=parseInt(h.substr(i,1)+h.substr(i+1,1),16);
for(;;){
i=0;
if(nkey){
while(nkey){
key.push(hash[i++]);
nkey--;
if(i==hash.length)break;
}
}
if(niv && i<hash.length){
while(niv){
iv.push(hash[i++]);
niv--;
if(i==hash.length)break;
}
}
if(!nkey && !niv)break;
for(i=0;i<hash.length;i++)hash[i]=String.fromCharCode(hash[i]);
h=Ext.ux.Crypto.SHA1.hash(hash.join("")+str);
for(i=0;i<h.length;i+=2)hash[i/2]=parseInt(h.substr(i,1)+h.substr(i+1,1),16);
}
return {key:key, iv:iv};
},

StringToPaddedData: function(str){
var data=new Array();
var i;
for(i=0;i<str.length;i++)data.push(str.charCodeAt(i));
var m = 16-(i%16);
for(i=0;i<m;i++)data.push(m);
return data;
},

PaddedDataToString: function(data){
var str="";
var i;
var pad=data[data.length-1];
for(i=0;i<(data.length-pad);i++)str+=String.fromCharCode(data[i]);
return str;
},

BytesToB64: function(bytes){
var i;
var b64="";
var brk=64;
//convert 3 bytes to 4 octets
for (i = 0; i + 2 < bytes.length; i += 3) {
b64 += B64Map[bytes[i] >>> 2];
b64 += B64Map[(bytes[i] << 4 & 0x3f) + (bytes[i + 1] >>> 4)];
b64 += B64Map[(bytes[i + 1] << 2 & 0x3f) + (bytes[i + 2] >>> 6)];
b64 += B64Map[bytes[i + 2] & 0x3f];
}
//handle remaining bytes
if (i < bytes.length) {
if (i + 1 < bytes.length) {
//convert 2 bytes to 3octets and 1 pad
b64 += B64Map[bytes[i] >>> 2];
b64 += B64Map[(bytes[i] << 4 & 0x3f) + (bytes[i + 1] >>> 4)];
b64 += B64Map[bytes[i + 1] << 2 & 0x3f];
b64 += B64Pad;
}
else {
//convert 1 bytes to 2octets and 2 pad
b64 += B64Map[bytes[i] >>> 2];
b64 += B64Map[bytes[i] << 4 & 0x3f];
b64 += B64Pad;
b64 += B64Pad;
}
}
//add new lines
for (i = brk; i < b64.length; i += brk) {
b64 = b64.substr(0,i-1)+"\n"+b64.substr(i-1);
}
return b64;
},

B64ToBytes: function(b64){
var i,j,o;
var octets=new Array();
var bytes=new Array();
//remove all none base 64 characters and convert to octets (including "=")
for (i = 0, j=0; i < b64.length; i++) {
if((o=InvB64Map[b64.substr(i,1)])!=null)octets[j++]=o;
}
//convert 4 octets to 3 bytes
for (i = 0, j = 0; i + 3 < octets.length; i+=4) {
bytes[j++]=(octets[i]<<2)+(octets[i+1]>>>4);
bytes[j++]=(octets[i+1]<<4&0xff)+(octets[i+2]>>>2);
bytes[j++]=(octets[i+2]<<6&0xff)+octets[i+3];
}
//handle remaining octets
if (i + 1 < octets.length) {
//convert 2 octets to 1 bytes
bytes[j++]=(octets[i]<<2)+(octets[i+1]>>>4);
if (i + 2 < octets.length) {
//convert 3 octets to 2 bytes
bytes[j++]=(octets[i+1]<<4&0xff)+(octets[i+2]>>>2);
}
}
return bytes;
},

Prepare: function(obj){
var i, ki, data;
var bits=256;
var o = {
mode: "cbc",
b64: false,
data: new Array(),
key: new Array(),
iv: new Array()
};
if(obj.mode=="ecb")o.mode=obj.mode;
if(obj.b64==true)o.b64=obj.b64;
if(typeof obj.pass == "string"){
if(obj.bits==128||obj.bits==192)bits=obj.bits;
ki=Ext.ux.Crypto.AES.StringToKeyIv(obj.pass, bits);
for (i = 0; i < ki.key.length; i++)o.key[i]=ki.key[i];
for (i = 0; i < ki.iv.length; i++)o.iv[i]=ki.iv[i];
}else{
if(!(obj.key instanceof Array) || (obj.key.length!=16&&obj.key.length!=24&&obj.key.length!=32)){
alert("obj.key must be a byte array of length 16, 24, or 32");
return null;
}
for(i=0; i<obj.key.length; i++){
if(typeof obj.key[i]!="number"){
alert("obj.key must be a byte array of length 16, 24, or 32");
return null;
}
o.key[i]=obj.key[i];
}
if(o.mode=="cbc"){
if(!(obj.iv instanceof Array)||obj.iv.length!=16){
alert("obj.iv must be a byte array of length 16");
return null;
}
for (i = 0; i < obj.iv.length; i++) {
if (typeof obj.iv[i] != "number") {
alert("obj.iv must be a byte array of length 16");
return null;
}
o.iv[i] = obj.iv[i];
}
}
}
if(typeof obj.data == "string"){
data=Ext.ux.Crypto.AES.StringToPaddedData(obj.data);
for (i = 0; i < data.length; i++)o.data[i]=data[i];
}else{
if (!(obj.data instanceof Array)||obj.data.length%16) {
alert("obj.data must be a byte array with a multiple of 16 length ");
return null;
}
for(i=0;i<obj.data.length;i++){
if (typeof obj.data[i] != "number") {
alert("obj.data must be a byte array with a multiple of 16 length ");
return null;
}
o.data[i] = obj.data[i];
}
}
o.round=Ext.ux.Crypto.AES.KeyExpansion(o.key);
return o;
},

//Encrypt expects obj specifying what and how to encrypt.
Encrypt: function(obj){
var cipher = new Array();
var input = new Array();
var output;
var i,j;
var roundKeys;
var o;

o=Ext.ux.Crypto.AES.Prepare(obj);
if(o==null)return null;

if(o.mode=="cbc")output=o.iv;
for (j = 0; j < o.data.length / 16; j++) {
for (i = 0; i < 16; i++) {
input[i] = o.data[j * 16 + i];
if(o.mode=="cbc")input[i]^=output[i];
}
output = Ext.ux.Crypto.AES.Cipher(input, o.round);
for (i = 0; i < 16; i++) cipher[j * 16 + i] = output[i];
}

if(o.b64)cipher=Ext.ux.Crypto.AES.BytesToB64(cipher);

return cipher;
},

Decrypt: function(obj){
var plain = new Array();
var input = new Array();
var copy = new Array();
var output;
var i,j;
var roundKeys;
var o;

o=Ext.ux.Crypto.AES.Prepare(obj);
if(o==null)return null;

if(o.b64)o.data=Ext.ux.Crypto.AES.B64ToBytes(obj.data);

if(o.mode=="cbc"){
for(i=0;i<o.iv.length;i++)copy[i]=o.iv[i];
}
for (j = 0; j < o.data.length / 16; j++) {
if (j>0 && o.mode == "cbc") {
for (i = 0; i < 16; i++)copy[i] = input[i];
}
for (i = 0; i < 16; i++) input[i] = o.data[j * 16 + i];
output = Ext.ux.Crypto.AES.InvCipher(input, o.round);
for (i = 0; i < 16; i++) {
plain[j * 16 + i] = output[i];
if(o.mode=="cbc")plain[j *16 + i]^=copy[i];
}
}
return Ext.ux.Crypto.AES.PaddedDataToString(plain);
}
}
}();

Diddy433
24 Dec 2008, 1:45 AM
Has anyone looked into updating the AES crypto functionality to use base64 encoding or is this already implemented? I see that in October 2008 Chris Vennuss updated his AES script to use base64.

dbraiden
15 Jan 2009, 8:34 AM
I finally got this to work.

If you need to decrypt this using openssl you will need to specify the -nosalt option.

Hope that helps

Dave

honzakuchar
12 Jul 2011, 9:37 AM
Hi, I really want try this extension. :-) It looks great from description! But where can I view examples or download source? Examples (from http://www.sencha.com/learn/legacy/Extension:Crypto) cannot be accessed:
- AES: http://ext.vosandhowden.com/ux/crypto/aes.cfm
- TEA: http://ext.vosandhowden.com/ux/crypto/tea.cfm
- SHA-1: http://ext.vosandhowden.com/ux/crypto/sha1.cfm

Regards.
Jan Kuchar

vtswingkid
7 May 2014, 8:43 AM
My code contributions in this thread are public domain.