I'm trying to encrypt text using WebCrypto. I convert the result to a utf8 string, then convert that to hex. The encryption/decryption works. However, I want to convert the data to hex. When I try to convert to hex and back, the result is different.
Here's the fiddle (use Chrome): https://jsfiddle.net/yxp01v5g/
The test code is here:
var text = "hello world";
var key = App.crypto.generateKey(16);
App.crypto.encrypt(text, key, function(encryptedText, iv){
console.log("encrypted text:", encryptedText, "iv", iv);
var encryptedTextHex = convertUtf8StringToHex(encryptedText);
console.log("encrypted text hex", encryptedTextHex);
var backToUtf8 = convertHexToUtf8(encryptedTextHex);
console.log("Back to utf8", backToUtf8);
console.assert(encryptedText == backToUtf8);
})
As you can see, I'm taking the result, converting it to hex, then converting it back to utf8, hoping for it to be equal to the original result. However, it's not.
Can anyone tell me what on earth I'm doing wrong?
I didn't dig too deep into the call-chain used in the fiddle to do the conversion, but it appears to try converting UTF-16/UCS-2 to byte size instead of an actually hex representation of the buffer content itself.
Here is one approach to convert the byte buffer content to hex string representation, and from hex string back to binary data.
It takes each byte in the buffer and produced a two-digit hex representation of its value, and concatenates it to a string.
The reverse takes two chars from the string representation and converts it back to a byte value representation.
// some bytes as Uint8Array
var random = crypto.getRandomValues(new Uint8Array(16)), i, str = "", allOK = true;
// convert to HEX string representation
for(i = 0; i < random.length; i++) str += pad2(random[i].toString(16));
console.log(str);
// convert back to byte buffer
var buffer = new Uint8Array(random.length);
for(i = 0; i < buffer.length; i++) buffer[i] = parseInt(str.substr(i<<1, 2), 16);
// check if same content
for(i = 0; i < buffer.length; i++) if (buffer[i] !== random[i]) allOK = false;
console.log("All OK?", allOK)
function pad2(s) {return s.length < 2 ? "0" + s : s}; // helper: pad to 2 digits
Related
I have base64 encoded binary data(~2.5MB). The data is consisting of c double value array. In c language it comes with no cost using this array - you just read the whole data into memory and use double* address to access any element.
However, now I need to use this data in javascript. I'm looking for most efficient way to be able to read this array from js code.
You could use this function in Node:
function doublesFromBase64(base64) {
let buff = Buffer.from(base64, 'base64');
let result = [];
for (let i = 0; i < buff.length; i += 8) {
result.push(buff.readDoubleLE(i));
}
return result;
}
To test it, I produced a sample base64 encoded string from the following piece of C code, which uses a function base64_encode found in this answer:
double arr[] = {15.9234, 2.05e30, -19};
size_t output_length;
char * result = base64_encode((unsigned char *) arr, 3* sizeof(double), &output_length);
printf("%s", result);
This outputs:
uECC4sfYL0Cjw3dB6N85RgAAAAAAADPA
I passed this string to the function at the top:
function doublesFromBase64(base64) {
let buff = Buffer.from(base64, 'base64');
let result = [];
for (let i = 0; i < buff.length; i += 8) {
result.push(buff.readDoubleLE(i));
}
return result;
}
let result = doublesFromBase64("uECC4sfYL0Cjw3dB6N85RgAAAAAAADPA");
console.log(result);
This outputs:
[ 15.9234, 2.05e+30, -19 ]
i have such a code to generate password written in Java
MessageDigest messageDigestPassword = MessageDigest.getInstance("SHA1");
messageDigestPassword .reset();
byte[] password = "password".getBytes();
messageDigestPassword .update(password);
byte[] encryptedPassword = messageDigestPassword .digest();
String date = "2019-10-22T11:33:13.393Z";
byte[] dateBytes = date.getBytes(StandardCharsets.UTF_8);
int offset = 0;
byte[] outputBytes = new byte[dateBytes.length + encryptedPassword .length];
System.arraycopy(dateBytes, 0, outputBytes, offset, dateBytes.length);
offset += dateBytes.length;
System.arraycopy(encryptedPassword , 0, outputBytes, offset, encryptedPassword .length);
MessageDigest finalMessageDigeset = MessageDigest.getInstance("SHA-1");
finalMessageDigeset.reset();
finalMessageDigeset.update(outputBytes);
byte[] finalPasswordBytes= finalMessageDigeset .digest();
String finalBase64Password = new String(Base64.encode(finalPasswordBytes));
and im trying to rewrite it to JavaScript to use it in postman with - CryptoJS
So far i have :
function wordArrayToByteArray(wordArray, length) {
if (wordArray.hasOwnProperty("sigBytes") &&
wordArray.hasOwnProperty("words")) {
length = wordArray.sigBytes;
wordArray = wordArray.words;
}
var result = [],
bytes,
i = 0;
while (length > 0) {
bytes = wordToByteArray(wordArray[i], Math.min(4, length));
length -= bytes.length;
result.push(bytes);
i++;
}
return [].concat.apply([], result);
}
function stringToBytes ( str ) {
var ch, st, re = [];
for (var i = 0; i < str.length; i++ ) {
ch = str.charCodeAt(i); // get char
st = []; // set up "stack"
do {
st.push( ch & 0xFF ); // push byte to stack
ch = ch >> 8; // shift value down by 1 byte
}
while ( ch );
// add stack contents to result
// done because chars have "wrong" endianness
re = re.concat( st.reverse() );
}
// return an array of bytes
return re;
}
var dateFixed = "2019-10-22T11:33:13.393Z";
var fixedDateBytes = stringToBytes(dateFixed);
var sha1Password= CryptoJS.SHA1("password");
console.log("sha1Password",sha1Password.toString(CryptoJS.enc.Hex));
var sha1PasswordBytes= wordArrayToByteArray(sha1Password, 20);
var concatedBytes= fixedDateBytes.concat(sha1PasswordBytes);
var finalShaPassWords= CryptoJS.SHA1(concatedBytes);
console.log("finalShaPassWords",finalShaPassWords.toString(CryptoJS.enc.Hex));
console.log("finalShaPassWords",finalShaPassWords.toString(CryptoJS.enc.Base64));
However unfortunatelly Base64 representations written in those 2 languages doesnt match.
I have checked and bytes from date are equal. Bytes from hashed password are not. So hashing after concat fails in JavaScript.
I have checked first password hashing and generated bytes and both of them are the same. So my guess line var sha1PasswordBytes= wordArrayToByteArray(sha1Password, 20); causes that line var finalShaPassWords= CryptoJS.SHA1(concatedBytes); returns bad value.
Can someone give me some idea what is wrong? Mayby it should be written diffrent ?
Since you are using CryptoJS anyway, you can also use the CryptoJS encoders and the WordArray#concat-method, which considerably simplifies the code:
var CryptoJS = require("crypto-js");
// Input
var inPwd = "password";
var inDate = "2019-10-22T11:33:13.393Z";
// Processing
var pwdHash = CryptoJS.SHA1(inPwd); // hash and convert to WordArray
var date = CryptoJS.enc.Utf8.parse(inDate); // convert to WordArray
var joinedData = date.clone().concat(pwdHash); // join date and hashed password
var joinedDataHash = CryptoJS.SHA1(joinedData); // hash joined data
var joinedDataHashB64 = CryptoJS.enc.Base64.stringify(joinedDataHash); // convert to Base64 string
// Output
console.log("Result: " + joinedDataHashB64 ); // Output: D235TBTZMfpSyB/CDl5MHAjH5fI=
The output of this code is the same as the output of the Java-code: D235TBTZMfpSyB/CDl5MHAjH5fI=
I need to split a hex string at every 00 byte. I tried this:
string.split('00');
But that causes splits at 5009, for instance, which is incorrect because it is splitting a byte in half.
In other words, it turns 5009 to [5, 9], which I don't want. But I do want it to turn af0059 to [af, 59].
Is it even possible to split bytes using regex, without cutting any bytes in half?
I could use a loop to seek through the string and only divide the string at even-number indices, but I would much prefer a regex expression.
Because of the byte sizes, you need to first split the string into byte-sizes, then map and finally join.
const string = "af00b9e00f70";
const res = string.split(/([\d\w]{4})/).filter(e => e).map(e => e.replace(/00([\d\w]{2})/, "$1").replace(/([\d\w]{2})00/, "$1")).join("");
console.log(res);
Here's a somewhat "old school' approach, but it demonstrates the principal. I say "old school' because we had to do this all the time back in the days of assembler coding. 'string' contains your long string of hex pairs (bytes). Here I convert it to byte values. Change the 'string' to whatever you want, but be sure it has an even number of hex digits. Call 'translate' to demonstrate it, and format the output into an alert() (or just output to the console)
var values = []; // output array
var string = "000102030405060708090a0b0c0d0e0f1FFFFEFDFCFBFAF9F8F7F6F5F4F3F2F0";
function getHexByteValues( string) {
var hex= "0123456789ABCDEF";
var outIx=0;
for (var i =0; i <= (string.length-2); i +=2) { // skip every other
//get higher and lower nibble
var hexdig1 = string.substring(i, i+1);
var hexdig0 = string.substring(i+1, i+2);
// for simplicity, convert alpha to upper case
hexdig1 = hexdig1.toUpperCase();
hexdig0 = hexdig0.toUpperCase();
// convert hex to decimal value.
// position in lookup string == value
var dec1 = hex.indexOf(hexdig1);
var dec0 = hex.indexOf(hexdig0);
// calc "byte" value, and add to values.
values[outIx++] = dec1 * 16 + dec0;
}
}
function translate(string) {
getHexByteValues(string);
var output="";
for (var i =0; i < values.length; i++) {
output += i + " = " + values[i] + "\r\n";
}
alert (output);
}
Maybe not the most elegant, but it works
const inp = "af00b9e00f70"
const out = inp.match(/.{1,2}/g).map(a=>a=="00"?"_":a).join("").split("_");
console.log(out);
I'm new to the concept of working with data on the binary level and am hoping someone can give me a hand here...
I'd like to build a binary buffer out of a series of hex numbers that are represented as strings.
For example,
suppose I have "xFCx40xFF" and I want to turn this into an array that looks like: 111111000100000011111111.
What's the best way to do this?
My best attempt seems to not be working:
var raw = "xFCx40xFF"
var end = raw.length-2;
var i = 1;
var j = 0;
var myArray = new Uint8Array(raw.len);
while (i < end) {
var s = raw.substr(i,2);
var num = parseInt(s,16);
i += 3;
myArray[j] = num;
j += 8;
}
Each 3 characters in string will represent 1 number in Uint8Array. Each number in Uint8Array will represent 8 bits. Your code was creating Uint8Array larger than needed and then placing values are wrong locations.
I have simplified the code to use a singe index i which represents the location in the Uint8Array. Corresponding location in string can be easily computed from i.
var raw = "xFCx40xFF"
var myArray = new Uint8Array(raw.length / 3);
for (var i = 0; i < raw.length / 3; i++) {
var str = raw.substr(3 * i + 1, 2);
var num = parseInt(str, 16);
myArray[i] = num;
}
Remove the 'x' character of your hex string and call parseInt() with the radix 16 and toString() with the radix 2 to get the binary string.
var raw = "xFCx40xFF";
var bin = parseInt(raw.split('x').join(''), 16).toString(2);
document.body.textContent = bin;
and if you need an array, just add .split('') at the end.
parseInt(raw.split('x').join(''), 16).toString(2).split('');
or iterate through each character.
I receive a binary file (biometric template) and I must convert the hexadecimal caracter to a ASCII caracter. But some hexadecimal caracter the programm do not convert, like hex = 95.
What is wrong? What must I to do for the program convert every ?
bellow the code:
var campo = document.getElementById('fileInput');
var hex = campo.toString();
var str = '';
for (var i = 0; i < prm.length; i += 2)
str += String.fromCharCode(parseInt(prm.substr(i, 2), 16));
You don't specify what you mean by "do not convert". If you meant decimal 95, there is an ASCII character but it is not printable (NAK). There is no ASCII character for hex 0x95 because ASCII is a 7-bit encoding (0-0x7f). And JavaScript strings are not ASCII, they're UCS-2.
https://mathiasbynens.be/notes/javascript-encoding