'Skip32 javascript endianness issue
I wanted to "quickly" try out a skip32 implementation in a form "client script" in ERPNext (javascript) and ended up with code like this:
frappe.web_form.validate = () => {
console.log('formname frappe.web_form.validate()');
data = frappe.web_form.get_values();
var cipher = new Skip32('s3cr3t k3y');
var enc = cipher.encrypt(42);
console.log('enc ' + value + ':' + enc);
var dec = cipher.decrypt(enc);
console.log('dec ' + value + ':' + dec);
... (frappe code) ...
};
function Skip32(key) {
this.key = new Uint8Array(10);
for (var i = 0; i < 10; i++) this.key[i] = key.charCodeAt(i % key.length);
// var _buf = new Buffer([
var ftable = new Uint8Array([
0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9,
0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28,
0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53,
0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2,
0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8,
0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90,
0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76,
0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d,
0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18,
0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4,
0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40,
0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5,
0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2,
0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8,
0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac,
0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46,
]);
//var ftable = new Uint8Array(_buf);
this.round16 = function(k, n){
var g1, g2, g3, g4, g5, g6;
g1 = (n>>8) & 0xff;
g2 = (n>>0) & 0xff;
g3 = ftable[g2^this.key[(4*k+0)%10]] ^ g1;
g4 = ftable[g3^this.key[(4*k+1)%10]] ^ g2;
g5 = ftable[g4^this.key[(4*k+2)%10]] ^ g3;
g6 = ftable[g5^this.key[(4*k+3)%10]] ^ g4;
return (g5<<8)+g6;
}
this.core = function(n,k,d){
var i, k, wl, wr;
wl = (((n>>24) & 0xff)<<8) + (((n>>16) & 0xff)<<0);
wr = (((n>>8) & 0xff)<<8) + (((n>>0) & 0xff)<<0);
for(i=0;i<24/2;i++){
wr ^= this.round16(k, wl) ^ k;
k+=d;
wl ^= this.round16(k, wr) ^ k;
k+=d;
}
return ((wr << 16) | wl)>>>0;
}
this.encrypt = function(n){
return this.core(n,0,1);
}
this.decrypt = function(n){
return this.core(n,23,-1);
}
this.checkEndian = function() {
var arrayBuffer = new ArrayBuffer(2);
var uint8Array = new Uint8Array(arrayBuffer);
var uint16array = new Uint16Array(arrayBuffer);
uint8Array[0] = 0xAA; // set first byte
uint8Array[1] = 0xBB; // set second byte
if(uint16array[0] === 0xBBAA) return "little endian";
if(uint16array[0] === 0xAABB) return "big endian";
else throw new Error("Something crazy just happened");
}
}
The skip32 code is adapted from this Node module source file: https://github.com/femto113/node-skip32/blob/master/skip32.js
This code worked in as much as it would encrypt then decrypt back to the original value. To confirm the ability to decode data generated on a different system (in Python3 using the "skippy" library) I first attempted to use the unit test data from https://github.com/pyrige/skippy/blob/master/skippy/tests/test_skippy.py which uses the key: b"s3cr3t k3y" and a test value of 42 but the expected result depends on whether the endianness of the host system being "little" or "big":
class SkippyTest(unittest.TestCase):
if sys.byteorder == "little":
test_data = {42: 2444721374, 4711: 3970196332,
935425436: 42, 798322584: 4711}
else:
test_data = {42: 406043987, 4711: 4097152607,
935425436: 2123491105, 798322584: 2445249305}
When I try to validate the javascript code using that key and the value 42 it generates 406043987 i.e. the "big-endian" expected result not 2444721374. Hence I added the "endian" test function and sure enough it gives the endianness as "little".
Both the Python and Javascript systems are Intel Core (so little-endian) and running the Python code with those test values generates the expected little-endian result 2444721374.
NB: ERPNext/Frappe seems to be irrelevant here (unsurprisingly) - entering the Skip32 function code directly at a web browser javascript console yields the same outcome.
Can anyone explain the anomalous result from this javascript code?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
