Why is the output of a Node AES128 Cipher 32 bytes long? - node.js

Here is my code:
var crypto = require('crypto')
function aese (key) {
return crypto.createCipher('aes128', key)
}
var x1 = crypto.randomBytes(16)
var y1 = crypto.randomBytes(16)
var a = aese(y1)
a.write(x1)
a.end()
var ct = a.read()
console.log(ct.length); //should be 16 but is 32

It's due to the padding that adds at least one byte, 16 bytes in gives at least 17 out which is padded to 32 due to the block size.
Try decreasing the number of encrypted bytes to 15 and you'll get 16 bytes as output.
Another option is to turn off padding;
var x1 = crypto.randomBytes(16)
var y1 = crypto.randomBytes(16)
var a = aese(y1)
a.setAutoPadding(false); <--- turn of auto-padding
a.write(x1)
a.end()
var ct = a.read()
console.log(ct.length); <--- gives 16 as output

Related

Cipher and decipher a number into hex in nodejs

I am looking for an efficient way to cypher and decypher a number using the same key.
This is not used for cryptography or encrypting anything so it doesn't need to be secure.
I have a unique number and I always want the same result out of the cypher. The cypher shouldn't be too long (more than 6 characters).
I do care about the speed as I will be making roughly 1000/millisecond cyphers.
The max number I will be looking to cypher is 100,000,000 and considering the alphanumeric = 26 lowercase letters + 26 uppercase letters and 10 numbers for 6 characters that's about 5.680 * 10^9 combinations which should suffice.
Example of pseudocode:
let num_to_cypher = 1;
let cypher = cypher_this_number(num_to_cypher); // ==> Ax53iw
let decypher = decypher_this_number(cypher); // ==> 1
let num_to_cypher_ex_2 = 12
let cypher_ex_2 = cypher_this_number(num_to_cypher_ex_2); // ==> 2R5ty6
let decypher_ex_2 = decypher_this_number(cypher_ex_2); // ==> 1
Edit 1:
I could have done something like below, but I can't define the cypher's length in this example and I don't care about encryption so I could go with something faster.
function encrypt(text){
let cipher = crypto.createCipher('aes128','d6F3Efeq')
let crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
function decrypt(text){
let decipher = crypto.createDecipher('aes128','d6F3Efeq')
let dec = decipher.update(text,'hex','utf8')
dec += decipher.final('utf8');
return dec;
}
I would use a good hash function. These 2 algorithms are pretty decent hash algorithms:
DJB2 (Daniel J Bernstein hash function:
Dr. Bernstein teaches maths and computer science at the University of Illinois at Chicago Circle. Can't find the original paper for this hash function.
NPM package at: https://www.npmjs.com/package/djb2a
FNV1a (Fowler–Noll–Vo hash function):
NPM package at https://www.npmjs.com/package/#sindresorhus/fnv1a
[Edited to note...]
Since it seems that you want a 2-way encoding, Base-64 is probably your friend here.
This will encode and decode any 32-bit signed integer value (ranging from -2,147,483,648 through +2,147,483,647 into 6 characters.
const {Buffer} = require('buffer');
const buf = Buffer.alloc(4);
const pad = [ '' , '', '==' , '=' ];
const MIN_INT32 = -2_147_483_648; // 0x80000000
const MAX_INT32 = +2_147_483_647; // 0x7FFFFFFF
function encode(n) {
if ( !Number.isInteger(n) || n < MIN_INT32 || n > MAX_INT32 ) {
throw new RangeError("n must be a valid 32-bit integer such that m is -2,147,483,648 >= m <= +2,147,483,647");
}
buf.writeInt32BE(n) ;
const b64 = buf.toString('base64').slice(0,-2);
return b64;
}
function decode(s) {
const b64 = s + pad[ s.length % 4 ];
buf.fill(b64, 'base64');
const n = buf.readInt32BE();
return n;
}
With that, it's a simple matter of:
onst n0 = 123_456_789;
const b64 = encode(n0);
const n1 = decode(b64);
console.log(`original: ${n0}` ) ;
console.log(`encoded: ${b64}` ) ;
console.log(`decoded: ${n1}` ) ;
Which produces:
original: 123456789
encoded: B1vNFQ
decoded: 123456789

node.js Buffer from Uint16Array

const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// Copies the contents of `arr`.
const buf1 = Buffer.from(arr);
// Shares memory with `arr`.
const buf2 = Buffer.from(arr.buffer);
console.log(buf1, buf2 );
// Prints: <Buffer 88 a0>
// Prints: <Buffer 88 13 a0 0f>
i look at the nodejs document where i see that
and my question is why buf1 is not <Buffer 88 13 a0 0f> ?
It is explained here that Buffer.from behaves as new Uint8Array() which can only contain numbers from 0 to 255 (1 byte) and here is stated that each value is converted and the result array length will be the same (so it can't have 4 elements). When converted, 2 byte value will be trimmed to 1 byte value, ignoring the second byte (88 13 -> 88, a0 0f -> a0).

Convert 3 output to one input at NODE-RED

Question is about Node-RED for raspberry pi 3. I have 3 input that give acceleration of X,Y,Z axis. I want to make one output from these 3 inputs. For this , I use √X^2+Y^2+Z^2 formula. According to my function my output is still 3 piece and giving NaN output when i debug. What should i do in Acc to Freq function
Here is my collecting X,Y,Z info from my sql.
var str = msg.payload;
str = str[0]['IX']; // Choose last data from IX column
a = str * 10; // Scaling the value
msg.payload = a
return msg;
var str = msg.payload;
str = str[0]['IY']; // Choose last data from IY column
b = str * 10; // Scaling the value
msg.payload = b
return msg;
var str = msg.payload;
str = str[0]['IZ']; // Choose last data from IZ column
c = str * 10; // Scaling the value
msg.payload = c
return msg;
And the function that i m try to calculate one output ( Acc to Freq )
var str = msg.payload;
var a;
var b;
var c;
str = Math.pow(a^2+b^2+c^2);
d = str * 10;
msg.payload = d;
return msg;
The point to remember is that a function node runs every time a message arrives, if you send it 3 separate messages then it will run 3 times. Also each function node is totally independent of all others, you can't declare a variable in one and use it in another (well there is something called the Context, but that's not particularly useful here)
You've not actually shown your flow so we are going to have to guess a little here, but you imply that all the starting values are coming from a single SQL query that returns multiple columns. If this is the case then you have 2 options.
Just do all the calculations in one place e.g. one function node with the following:
var str = msg.payload;
var strA = str[0]['IX']; // Choose last data from IX column
var a = strA * 10; // Scaling the value
var strB = str[0]['IY']; // Choose last data from IY column
var b = strB * 10; // Scaling the value
var strC = str[0]['IZ']; // Choose last data from IZ column
var c = strC * 10; // Scaling the value
var strC = Math.pow(a^2+b^2+c^2);
var d = strC * 10;
msg.payload = d;
return msg;
You can run the output of your current 3 function nodes into a Join node set to collect 3 values. This will generate a new msg object with a payload containing an array of the 3 values. You can then modify your final function node as follows:
var a = msg.payload[0];
var b = msg.payload[1];
var c = msg.payload[2];
var d = Math.pow(a^2+b^2+c^2) * 10 ;
msg.payload = d;
return msg;

TripleDes CBC Nodejs implementation throuble

i need to replicate in Nodejs the results of the 3DS CBC encrypt in http://tripledes.online-domain-tools.com/.
This is my code:
const crypto = require('crypto');
const cipher = crypto.createCipher('des-ede3-cbc', key);
password = Buffer.from('MYPASS', 'utf8');
let encrypted = [cipher.update(password)];
encrypted.push(cipher.final());
encrypted = Buffer.concat(encryptedArr);
console.log(encrypted.toString('hex'));
The result of tripledes.online-domain-tools.com is:
Note that the result should be 59 30 20 02 a5 8c dd 5e, but my code gives me 33 97 d8 b0 e3 00 d1 53.
What am i missing?
Edit2:
Following your suggestions, I changed my code (Also added some Tests made with the guide of the NIST Publication):
const crypto = require('crypto');
function encrypt (inputkey, keyformat, password, passwordformat) {
let shortkey = Buffer.from(inputkey, keyformat);
let key = Buffer.alloc(24);
key.fill('\0');
for (i = 0; i < shortkey.length; i++) {
key[i] = shortkey[i];
}
let IV = Buffer.alloc(8);
const cipher = crypto.createCipheriv('des-ede3-cbc', key, IV);
password = Buffer.from(password, passwordformat);
let encryptedArr = [cipher.update(password)];
encryptedArr.push(cipher.final());
encrypted = Buffer.concat(encryptedArr);
return encrypted;
}
console.log(encrypt('1046913489980131','hex','0000000000000000','hex')); // works
console.log(encrypt('1007103489988020','hex','0000000000000000','hex')); // works
console.log(encrypt('10071034C8980120','hex','0000000000000000','hex')); // works
console.log(encrypt('1046103489988020','hex','0000000000000000','hex')); // works
console.log(encrypt('MYKEY','utf8','MYPASS','utf8')); // fails
Every Permutation Operation Known Answer Test of the NIST works great, but several other examples (including the one of the image) just fails
The reason i'm testing with this shady page is because my service provider is using it as reference.
This site made me some troubles for some time , well here is the implementation it uses internally to expand the key to be a 24 bytes !
i am going to talk about tripledes but i guess this would apply to other algorithms used by this site
step 1
it first checks if the key entered has the length that it expects it to be, (you can find a table at the bottom of that site telling the length of key for each Encryption algorithm)
if it does not it will complete with 0x00 bytes like this:
var key;// is a string containing the bytes wich will be used to encrypt the msg
var nullByte = 0x00;
var padding_needed;
for (var i=key.length ;i < expected_key_length ; ++)
{padding_needed =padding_needed + nullBute.tostring(16); }
key = key + padding_needed
so for example the length that it expects for 3DES is 24 bytes ; if you happen to enter just 15 bytes like this (112233445566778899aabbccddeeff) it will be like if you entered (112233445566778899aabbccddeeff00)
step2
in the case of tripledes the algorithm to expand the 16 bytes to 24 bytes key (which is the key length required by the algorithm) this site has a simple approach to do that
it copies the first 8 bytes and append it to the end of the key like this
key =key + key.substring(0,8);
and that is the key that is going to be given to the 3DES encryption function to work with
this simple approache is not used by openssl for example , open ssl uses the first 8 bytes of the MD5 of the key ,and append them to the 16 bytes of the original key to get the 24 bytes key that is required by 3DES, like this
key = key + (MD5(key)).substring(0,8);
Summary
in that tool if you enter the key 112233445566778899AABBCCDDEEFF is the same as if you entered 112233445566778899AABBCCDDEEFF00 and same as if you entered 112233445566778899AABBCCDDEEFF001122334455667788 so to solve your problem you should give your function the complete 24 bytes of key that you gave to that site and you will surely get the same results, beacause nodejs is probably is doing the same thing as openssl does to expand the key(uses md5)
PS
if you are using the cbc mode which is your case try to specify the IV to be 8 bytes of \x00 like this "0000000000000000"
the results will be the same !!
here is a working implementation of your code you can check it in the site
const crypto = require('crypto');
function encrypt (inputkey, keyformat, password, passwordformat) {
let shortkey = Buffer.from(inputkey, keyformat);
let key = Buffer.alloc(24);
key.fill('\0');
for (i = 0; i < shortkey.length; i++) {
key[i] = shortkey[i];
}
let IV = Buffer.alloc(8);
var expansionStart = shortkey.length>16?shortkey.length:16;
for (i=expansionStart;i<24;i++){
key[i]=key[i-expansionStart];
}
console.log(key);
const cipher = crypto.createCipheriv('des-ede3-cbc', key, IV);
password = Buffer.from(password, passwordformat);
let encryptedArr = [cipher.update(password)];
encryptedArr.push(cipher.final());
encrypted = Buffer.concat(encryptedArr);
return encrypted;
}
var enc = encrypt("112233445566778899AABBCCDDEEFF","hex","password","utf8");
console.log(enc);

When reading a WAV file, dataID is printed as "fact" and not "data"

I'm new to audio playback and have spent the day reading over the wav file specification. I wrote a simple program to extract the header of a file but right now my program always returns false as the DataID keeps returning as "fact" instead of "data".
There are a few reasons I believe this could be happening.
The file I am reading in has a format size of 18, whereas this resource states a valid PCM file should have a format size of 16.
The format code of the file I am reading is 6, meaning it has probably been compressed.
The value of dataSize is far too small (only 4). Even though the file has 30 seconds of playback when ran through VLC or Windows Media Player.
The code I am using is as follows:
using (var reader = new BinaryReader(File.Open(wavFile, FileMode.Open)))
{
// Read all descriptor info into variables to be passed
// to an ASWAVFile instance.
var chunkID = reader.ReadBytes(4); // Should contain "RIFF"
var chunkSize = reader.ReadBytes(4);
var format = reader.ReadBytes(4); // Should contain "WAVE"
var formatID = reader.ReadBytes(4); // Should contain "fmt"
var formatSize = reader.ReadBytes(4); // 16 for PCM format.
var formatCode = reader.ReadBytes(2); // Determines linear quantization - 1 = PCM, else it has been compressed
var channels = reader.ReadBytes(2); // mono = 1, stereo = 2
var sampleRate = reader.ReadBytes(4); // 8000, 44,100 etc
var byteRate = reader.ReadBytes(4); // SampleRate * Channels * BitsPerSample / 8
var blockAlign = reader.ReadBytes(2); // Channels * BitsPerSample / 8
var bitsPerSample = reader.ReadBytes(2); // If mono 8, if stereo 16 etc.
var padding = byteToInt(formatSize);
// Read any extra values so we can jump to the data chunk - extra padding should only be set here
// if formatSize is 18
byte[] fmtExtraSize = new byte[2];
if (padding == 18)
{
fmtExtraSize = reader.ReadBytes(2);
}
// Read the final header information in, we can then set
// other
var dataID = reader.ReadBytes(4); // Should contain "data"
var dataSize = reader.ReadBytes(4); // Calculated by Samples * Channels * BitsPerSample / 8
// Check if the file is in the correct format
if (
System.Text.ASCIIEncoding.Default.GetString(chunkID) != "RIFF" ||
System.Text.ASCIIEncoding.Default.GetString(format) != "WAVE" ||
System.Text.ASCIIEncoding.Default.GetString(formatID) != "fmt" ||
System.Text.ASCIIEncoding.Default.GetString(dataID) != "data"
)
{
return false;
}
//file = new ASWAVFile();
}
If I dump the values of chunkID, format, formatID and dataID I get:
RIFF, WAVE, fmt, fact
Causing the method to return false. Why is this happening?
The RIFF specification doesn't require the 'data' chunk to follow the 'fmt' chunk. You may see some files that write a 'pad' chunk after the 'fmt' chunk to ensure page alignment for better streaming.
http://en.wikipedia.org/wiki/WAV
Also the format code indicates the audio compression type, as you noted. Valid format codes are in mmreg.h (on Windows): (Format 6 is aLaw, indeed a compression type).
http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/Docs/MMREG.H
Your best bet is to write code that reads chunk headers, checks for the type you want, and skip past it to the next chunk if you can't find what you are looking for.

Resources