Different blowfish encryption results - javascript

I am trying to replicate a particular function from our SAP system to a web site and a part of the flow is a blowfish encryption. I looked around for Blowfish encryption libraries for Javascript and implemented it into my js code.
However, upon comparison with the original SAP flow, the results of our blowfish encryptions are different.
The only thing that's different is that SAP blowfish uses UTF-16LE. I've tried converting my password and the text to UTF-16LE but I cannot get the same results from the original system.
I've found these two codes while searching around (these 2 converts/decodes from UTF8-UTF16 and vice versa)
function strEncodeUTF16(str) {
var byteArray = new Uint8Array(str.length * 2);
for (var i = 0; i < str.length; i++) {
byteArray[i*2] = str.charCodeAt(i); // & 0xff;
byteArray[i*2+1] = str.charCodeAt(i) >> 8; // & 0xff;
}
return String.fromCharCode.apply(String,byteArray);
}
function decodeUTF16LE( binaryStr ) {
var cp = [];
for( var i = 0; i < binaryStr.length; i+=2) {
cp.push(
binaryStr.charCodeAt(i) |
( binaryStr.charCodeAt(i+1) << 8 )
);
}
return String.fromCharCode.apply( String, cp );
}
The blowfish library I'm using is from the Dojo Toolkit:
Blowfish.js from Dojo Toolkit 1.8.1
A sample test case would be:
Password: 7F30742A2
Text: 329
Result: B33663DFAC049492
However, when I try it on my end
var encrypted = blowfish.encrypt(id, key, {outputType:1, cipherMode: 0});
My result is:
ef701b0e904b10c3
I am not sure where the difference is happening. Any thoughts?

Related

Generating identical pseudorandom numbers on client and server

I have a web application using JavaScript on the client side and C# on the server side. I need to be able to generate sets pseudorandom numbers - given a shared seed - that are identical on the client and server sides. Is there a standard way of doing this? Obviously it's no good using the built-in PRNG libraries for the respective languages because their algorithms are going to differ.
I don't want to use a server endpoint to provide the client with the random numbers because my client application requires quick responses and that would add latency. It would work but wouldn't be ideal.
Here's a javascript implementation of the C version of xorshift128+. Per the wikipedia article, the xorshift128+ pseudo random number generator (PRNG) passes BigCrush (empirical randomness testing).
Note that xorshift128+ is used by major browsers when implementing Math.random, so it's a solid algorithm, although not crypto solid...
Note also that the local variables within method nextValue make use of a BigUint64Array, as this automatically reduces any intermediate results to 64 bits.
class XorShift128 {
#state;
static bitMask64 = ( 1n << 64n ) - 1n;
static bitMask32 = ( 1n << 32n ) - 1n
constructor( uint128Seed ) {
this.#state = new BigUint64Array( [ ( uint128Seed >> 64n ) & XorShift128.bitMask64, uint128Seed & XorShift128.bitMask64 ] );
}
get nextValue() {
let r = new BigUint64Array( this.#state );
// C version t = r[0], s = r[1]
this.#state[ 0 ] = r[ 1 ];
r[ 0 ] ^= r[ 0 ] << 23n;
r[ 0 ] ^= r[ 0 ] >> 18n;
r[ 0 ] ^= r[ 1 ] ^ ( r[ 1 ] >> 5n );
this.#state[ 1 ] = r[ 0 ];
return Number( ( r[ 0 ] + r[ 1 ] ) & XorShift128.bitMask32 );
}
}
console.log( `Set the seed to 0x8a5cd789635d2dff121fd2155c472f96n and generate 5 values...` );
let PRNG0 = new XorShift128( 0x8a5cd789635d2dff121fd2155c472f96n );
for ( let i = 0; i < 5; i++ ) {
console.log( PRNG0.nextValue );
}
console.log( `Let's do it again...` );
let PRNG1 = new XorShift128( 0x8a5cd789635d2dff121fd2155c472f96n );
for ( let i = 0; i < 5; i++ ) {
console.log( PRNG1.nextValue );
}
For completeness sake, here's the same algorithm in C.
//gcc 7.4.0
#include <stdint.h>
#include <stdio.h>
struct xorshift128p_state {
uint64_t x[2];
};
/* The state must be seeded so that it is not all zero */
uint64_t xorshift128p(struct xorshift128p_state *state)
{
uint64_t t = state->x[0];
uint64_t const s = state->x[1];
state->x[0] = s;
t ^= t << 23;
t ^= t >> 18;
t ^= s ^ (s >> 5);
state->x[1] = t;
return t + s;
}
main() {
struct xorshift128p_state seed;
seed.x[0] = 0x8a5cd789635d2dff;
seed.x[1] = 0x121fd2155c472f96;
uint64_t bitMask32 = ( 1ULL << 32 ) - 1ULL;
int i;
for ( i =0; i < 5; i++ ) {
uint64_t rv = xorshift128p( &seed );
printf( "%ld\n", rv & bitMask32 );
}
}
C Code Snippet
Add an API endpoint on the server in c# to return individual or an array of random numbers, then call that from the client.
calls to the server do not have to be inefficient, depending on your logic and the frequency of the call, it might even make sense to call this from the server, especially if consistency of the values is so important, this might be an X-Y Problem, what is the frequency of the calls, what is the highest latency that you can tolerate and what type of response times are you recording from your implementation.
Yes, there is a standard solution to problems like this (replicating logic in the client and the server) and that is to use the same random number generator algorithm and the same seed value. This is for instance how we can replay specific hands in card games.
A pure C# solution that allows you to use the same code in the client and the server would be to consider Blazor instead of javascript. Other solutions would be to implement your own algorithm or to find another one that has been ported to both C# and javascript.
So basically I've come to the conclusion that the only really reliable way I could get exactly the same PRNG on both the server and client side is to use the same language on both sides - for example C# using Blazor on the client-side and C#.NET on the server-side - and to create a class in that language that has an identical implementation for the server-side and client-side code, which would get shared.
A good class to copy/paste for such an implementation would probably be the XoshiroImpl random number generator class which seems to be the latest PRNG implementation being used by .NET core.
As it is I'm using JS for the client and C# for the server, so I had to solve the problem in a different way.

rijndael-128 cbc javascript does not return correct like php mcrypt

In php i use mcrypt to encrypt my string with key and lv...now i im porting my php code project to node js and need to get same encrypted string in javascript like in php... my data is the following:
lv: 968kjnv0myizvjio
key: 9qdx524o5rzytekr
string: androidtest
encoding: rijndael-128
mode: cbc
In php i get this correct encrypted string:
9620825aa10ce13d9e886b6dec146074
In javascript(node library) i get this:
6c6943435771454d34543265694774743742526764413d3d
My code is this:
var MCrypt = require('mcrypt').MCrypt;
var desEcb = new MCrypt('rijndael-128', 'cbc');
desEcb.open('9qdx524o5rzytekr', '968kjnv0myizvjio'); // we are set the key and lv
var ciphertext = desEcb.encrypt('androidtest');
console.log(bin2hex(ciphertext.toString('base64')));
function bin2hex(s) {
var i
var l
var o = ''
var n
s += ''
for (i = 0, l = s.length; i < l; i++) {
n = s.charCodeAt(i).toString(16)
o += n.length < 2 ? '0' + n : n
}
return o
}
I im using this library:
https://github.com/tugrul/node-mcrypt
How can i get same result in node js (javascript) like in PHP posted above?
Or do you know another library that works in node js to get same result as PHP?
Or maybe write custom function to get this above archived?
Firstly, don't convert the ciphertext to base64 - you don't in PHP, so that's one point of different
You don't need your bin2hex function, because node can do it for you
var ciphertext = desEcb.encrypt('androidtest');
console.log(ciphertext.toString('hex')); //9620825aa10ce13d9e886b6dec146074

Google Apps Script random string generating

i am new to Google apps script, i want to create string of random characters in the code given below in variable body2.
function myfunction() {
var files = DriveApp.getFiles();
while (files.hasNext(`enter code here`)) {
Logger.log(files.next().getName());
}
var recipient = Session.getActiveUser().getEmail();
var subject = 'A list of files in your Google Drive';
var body1 = Logger.getLog();
var body2;
for(var i=0;i<6;i++)
{
body2[i]=BigNumber.tostring("Math.floor(Math.random()*11)");
}
body=body1+body2;
MailApp.sendEmail(recipient, subject, body);
};
but when i run this function, it says "TypeError: Cannot find function tostring in object 0. (line 12, file "Code") " i can't understand how to solve this error?
Why we have to multiply random by 11 , can it be multiplied with any integer number?
what if i want that string in only capital letters.!
Some other question
1) i don't have enough knowledge of JavaScript, is it good to learn GAS directly?
2) i can't find proper written material or documentation for GAS , the material available at Google's official site is seems to be updating time by time , what to do then ? any link to material would help me .!
I guess I just figured
function randomStr(m) {
var m = m || 15; s = '', r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i=0; i < m; i++) { s += r.charAt(Math.floor(Math.random()*r.length)); }
return s;
};
Hope someone finds it helpful.
As for a random string use this its better:
Math.random().toString(36). 36 is the base thus will use letters and numbers in the string.
As for gas documentation, the official page is pretty complete. It changes because it constantly improves and adds new services.
I have this charIdGeneration() in my GAS library
function charIdGenerator()
{
var charId ="";
for (var i = 1; i < 10 ; i++)
{
charId += String.fromCharCode(97 + Math.random()*10);
}
//Logger.log(charId)
return charId;
}

How to load an Array (of numbers) into a google app script Byte[]

I have an Array (of numbers) in Google Apps Script, and I want to convert it to base64. I could of course use a simple open-source library such as this one.
However GAS already provides functions for this using Utilities.base64Encode(Byte[])
but to call this function I need a Byte[] not Number[].
Therefore the following script gives an error: (Cannot convert Array to (class)[].)
function testBase64Encode()
{
var bytes = [];
for (var i = 0; i < 255; i++) bytes.push(i);
var x = Utilities.base64Encode(bytes)
}
Normally Byte[]'s come directly out of a Blob's GetBytes() function, however in my case the Array (of numbers) comes out of zlib encryption lib.
So I am trying to find a way to convert that Number Array to a Byte[], acceptable for use with Utilities.base64Encode(Byte[]).
I did try to create a Byte myself and put them into an Array, however the following code also gives an error: (ReferenceError: "Byte" is not defined.)
var b1 = new Byte();
I did some more testing, and it seems to work as long as the value in the bytes' numeric values are 128 or lower. I find this weird because a byte should go up to 255.
The following code runs fine for 'bytes' but fails for 'bytes2' because there is a value greater than 128:
function testByteArrays()
{
var bytes = [];
for (var i = 0; i < 128; i++) bytes.push(i);
var x = Utilities.newBlob(bytes)
var bytes2 = [];
for (var i = 0; i < 129; i++) bytes2.push(i);
var x = Utilities.newBlob(bytes2)
}
...a byte should go up to 255.
But not in Two's complement notation... in that case, the bytes should be in the range [-128..127], where the high-order bit is reserved as a sign bit. Given a positive integer i, we need to calculate the two's complement if it is greater than 127. That can be done by subtracting 28 (256). Applying that to your first example:
function testBase64Encode()
{
var bytes = [];
for (var i = 0; i < 255; i++) bytes.push(i<128?i:i-256);
var x = Utilities.base64Encode(bytes)
}
This will avoid the error message you were receiving (Cannot convert Array to (class)[].). Ideally, you should also ensure that the number values start in the range 0..255.

Does slowAES allow/support zero padding?

I'm trying to perform AES encryption in CBC mode with zero padding. Does anyone know if aesSlow supports zero padding? Based on my reading of the code it doesn't and if that's the case; can anyone tell me why?
I'm using a 3rd party API which requires this encryption method.
jsfiddle.net/NMATS/2 is my current POC. I'll bemoving it to node once it's debugged. Also the inputs are similar but different for security.
Cheers,
Denis
It looks like you are correct. It appears to use PKCS7. Your options then are:
Pad it with 0's yourself and discard the last block of ciphertext
Edit the code and make the padding function do zero-padding (beware of license restrictions - I didn't look at the license)
As to why, I'd guess they just haven't had a need to do it or the time to implement it yet.
If you go with option 1, PKCS7 adds a full block of 0x10 bytes if your plaintext is already the multiple of a block size. Therefore, you can just pad your plaintext with 0x00 bytes to make it a multiple of a block size and encrypt it. Then you would drop the last 128-bits of the ciphertext (which is just 16 bytes of 0xFF encrypted). You will end up with a compatible result.
If you go with option 2, I'm not sure which implementation you are using, but I think they're all simple enough.
Here is the padding function for the Javascript implementation:
padBytesIn: function(data) {
var len = data.length;
var padByte = 16 - (len % 16);
for (var i = 0; i < padByte; i++) {
data.push(padByte);
}
},
Here is what you would change it to:
padBytesIn: function(data) {
var len = data.length;
if( len % 16 > 0 ){
var padLen = 16 - (len % 16);
for (var i = 0; i < padLen; i++) {
data.push(0);
}
}
},

Categories