Browser buffer to string conversion is not same in browser and nodejs - javascript

I have encountered an interesting issue.
I'm using node v8.1.4
I have the following buffer.
[ 191, 164, 235, 131, 30, 28, 164, 179, 101, 138, 94, 36, 115, 176, 83, 193, 9, 177, 85, 228, 189, 193, 127, 71, 165, 16, 211, 132, 228, 241, 57, 207, 254, 152, 122, 98, 100, 71, 67, 100, 29, 218, 165, 101, 25, 17, 177, 173, 92, 173, 162, 186, 198, 1, 80, 94, 228, 165, 124, 171, 78, 49, 145, 158 ]
When i try to convert it to utf8 using nodejs and using browser i get different results. even length of string is not the same.
Is there a way to convert string to utf8 in browser same way as node js do?
It seems that some characters that some sequence which nodejs replace to U+FFFD are more lengthy than the replaced sequence in browser. so output utf8 string is different
Code i use in browser and in nodejs is same
i have buffer object tmpString
tmpString.toString('utf-8')
tmpString.toString('utf-8').length differs in browser and nodejs for the same source bytes.
In nodejs i use native buffer implementation, for browser webpack loads polyfill (feross/buffer i think)
i think more accurately would say that i try to interpret buffer bytes as UTF8 string.

Have you tried the TextEncoder/TextDecoder APIs? I've used them for converting strings in both nodejs and the browser and haven't seen any differences.
E.g.:
const encoder = new TextEncoder('utf-8');
const decoder = new TextDecoder('utf-8');
const foo = 'Hello world!';
const encoded = encoder.encode(foo);
console.log(encoded);
const decoded = decoder.decode(encoded);
console.log(decoded);

Related

Unable to convert bytes Uint8Array to string in javascript

I am unable to decrypt this Uint8Array
Uint8Array(32) [
174, 157, 255, 238, 54, 143, 97, 132,
70, 243, 7, 249, 98, 188, 68, 170,
53, 82, 78, 9, 96, 226, 182, 160,
131, 79, 3, 147, 153, 34, 205, 162
]
using this code
const string = new TextDecoder().decode(hash);
console.log(string);
I get this: ����Kc2Jk�&an↕�9���&��h-Lﺠ�Ԋ
I've also tried with many online converters but it says there's some problem with the byte array. This byte array is a response from an API.
Where Am I wrong? How can I convert it properly?

Hyperledger Fabric API returns a buffer type data, how do i convert buffer to string of this data in javascript

i am building a blockchain on hyperledger fabric (node.js SDK).
https://hyperledger.github.io/fabric-sdk-node/release-1.4/global.html#BlockchainInfo__anchor
i call the api BlockchainInfo and get a json format response, which includes currentBlockHash
the offical document shows that the response data type of currentBlockHash is Array< byte >
such as the following data.
i would like to convert this buffer to string but have no idea what to do.
thanks for your reading the question.
{ buffer:
{ type: 'Buffer',
data:
[ 8,
207,
230,
17,
18,
32,
124,
143,
73,
40,
171,
42,
251,
237,
193,
138,
36,
92,
58,
57,
254,
56,
144,
96,
54,
201,
242,
64,
10,
111,
150,
28,
198,
187,
196,
118,
97,
160,
26,
32,
16,
160,
154,
19,
11,
179,
147,
11,
38,
16,
150,
190,
126,
17,
121,
123,
200,
7,
71,
27,
241,
103,
54,
188,
196,
248,
178,
88,
48,
115,
186,
133 ] },
offset: 6,
markedOffset: -1,
limit: 38,
littleEndian: true,
noAssert: false }
here is the origin response data
{"height":{"low":291663,"high":0,"unsigned":true},"currentBlockHash":{"buffer":{"type":"Buffer","data":[8,207,230,17,18,32,124,143,73,40,171,42,251,237,193,138,36,92,58,57,254,56,144,96,54,201,242,64,10,111,150,28,198,187,196,118,97,160,26,32,16,160,154,19,11,179,147,11,38,16,150,190,126,17,121,123,200,7,71,27,241,103,54,188,196,248,178,88,48,115,186,133]},"offset":6,"markedOffset":-1,"limit":38,"littleEndian":true,"noAssert":false},"previousBlockHash":{"buffer":{"type":"Buffer","data":[8,207,230,17,18,32,124,143,73,40,171,42,251,237,193,138,36,92,58,57,254,56,144,96,54,201,242,64,10,111,150,28,198,187,196,118,97,160,26,32,16,160,154,19,11,179,147,11,38,16,150,190,126,17,121,123,200,7,71,27,241,103,54,188,196,248,178,88,48,115,186,133]},"offset":40,"markedOffset":-1,"limit":72,"littleEndian":true,"noAssert":false}}
I think the JSDoc is misleading in this case. I think the currentBlockHash will actually be a Node.js Buffer (or possibly a protobuf implementation that emulates the behaviour of a Buffer). You can convert a Buffer into a string by calling currentBlockHash.toString().
I have observed some cases where calling toString() on a protobuf Buffer implementation gives a debug string rather than a string representation of the content of the buffer so I tend to specify an encoding argument just to be safe.
In the case of a hash it may be more convenient to see it as a hex string rather than utf8 (which would be the default) anyway, so I would try currentBlockHash.toString('hex')
See here for more information on Buffers: https://nodejs.org/docs/latest-v10.x/api/buffer.html

crypto.subtle.importKey in Chrome throws a DOMException, while Firefox works well

I'm trying to import an ECDSA public key as follows:
ua8 = new Uint8Array( [48, 86, 48, 16, 6, 4, 43, 129, 4, 112, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 124, 78, 186, 4, 136, 215, 226, 113, 200, 80, 93, 199, 105, 63, 47, 60, 193, 162, 180, 226, 160, 164, 9, 183, 122, 42, 97, 201, 99, 128, 54, 227, 193, 220, 229, 75, 186, 223, 201, 227, 229, 159, 159, 67, 205, 3, 126, 74, 211, 202, 122, 66, 185, 150, 74, 152, 192, 177, 81, 155, 106, 237, 212, 146] );
crypto.subtle.importKey( "spki", ua8, { name: "ECDSA", namedCurve: "P-256", }, false, ["verify"] );
In Firefox, this works well, but in Chrome I get a DOMException.
I want it to work in both browsers. How can I fix it?
According to the Chromium WebCrypto documentation:
Chromium's WebCrypto implementation supports all of the key formats - "raw", "spki", "pkcs8", "jwk", with the following caveats:
There are differences in DER key format handling between Web Crypto implementations. Where possible for compatibility prefer using "raw" keys or "jwk" which have better interoperability.
When importing/exporting "spki" and "pkcs8" formats, the only OIDs supported by Chromiumare those recognized by OpenSSL/BoringSSL.
in particular, it says that:
Importing ECDH keys does not accept id-ecDH. The OID must instead be id-ecPublicKey (This can cause problems importing keys generated by Firefox; use "raw" EC keys as a workaround; Chromium in this case is not spec compliant)
(The bug tracker link is giving me a 500 Internal Server Error, but that might be temporary.)
Looking at your key in an ASN.1 decoder, it contains the following data:
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.132.112
OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
BIT STRING (520 bit) 0000010001111100010011101011101000000100100010001101011111100010011100…
The object identifier 1.3.132.112 is precisely the "id-ecDH" identifier that Chrome does not recognize. For what it's worth, a key exported from Chrome instead has the OID 1.2.840.10045.2.1 ("ecPublicKey").
As the linked documentation page suggests, as a workaround you may wish to switch from the "spki" format to "raw" (or to "jwk", which is JSON-based).

Crypto.js decrypt with key and iv (vector) in byte arrays

I have to decrypt some strings which are AES encrypted.
Example encrypted string: 129212143036071008133136215105140171136216244116
I have a key, and a vector (iv) supplied to me in a byte-array format:
Key: [ 123, 217, 20, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 115, 222, 209, 241, 24, 175, 144, 175, 53, 196, 29, 24, 23, 17, 218, 131, 226, 53, 209 ]
Vector (iv): [ 146, 66, 191, 151, 23, 3, 113, 119, 231, 131, 133, 112, 79, 32, 114, 136 ]
I should be able to decrypt the string and get:
Correct output: testtest
I'm trying to use Crypto.js but I can't find a way to use the supplied key and vector. I can't find a way to convert the byte-arrays to hex.
var encrypted = '129212143036071008133136215105140171136216244116';
var key = CryptoJS.enc.Hex.parse([ 123, 217, 20, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 115, 222, 209, 241, 24, 175, 144, 175, 53, 196, 29, 24, 23, 17, 218, 131, 226, 53, 209 ]);
var iv = CryptoJS.enc.Hex.parse([ 146, 66, 191, 151, 23, 3, 113, 119, 231, 131, 133, 112, 79, 32, 114, 136 ]);
var decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv: iv });
console.log('Output: '+decrypted.toString(CryptoJS.enc.Utf8)); //Should be "testtest"
I would be so grateful if anyone could show me how to decrypt the example string using the key and vector with Crypto.js OR any other js method.
Thanks so much for any help,
Kind regards
I can't manage to decrypt your original string, but I can successful use it to encrypt and decrypt a new string. In your initial implementation, an error occurs in aes.js because it expects key and iv to be strings rather than arrays. I have corrected this code example below:
//var encrypted = '129212143036071008133136215105140171136216244116';
var key = CryptoJS.enc.Hex.parse(CryptoJS.lib.ByteArray([123, 217, 20, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 115, 222, 209, 241, 24, 175, 144, 175, 53, 196, 29, 24, 23, 17, 218, 131, 226, 53, 209]));
var iv = CryptoJS.enc.Hex.parse(CryptoJS.lib.ByteArray([146, 66, 191, 151, 23, 3, 113, 119, 231, 131, 133, 112, 79, 32, 114, 136]));
var message = 'testest'
var encrypted = CryptoJS.AES.encrypt(message, key, {
'iv': iv
});
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
'iv': iv
});
document.write('Output: ' + decrypted.toString(CryptoJS.enc.Utf8)); //Should be "testtest"
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/pad-nopadding-min.js"></script>
<script src="https://greasyfork.org/scripts/6696-cryptojs-lib-bytearray/code/CryptoJSlibByteArray.js"></script>
Bit of an old post, and I think the API has changed somewhat since then as it now uses WordArray rather than ByteArray.
But I was running into the same issue. Turns out, you can simply provide a base64-encoded string into decrypt(). So all you need to do is to create a base64-encoded string from your original message. I'm not sure what format your message is in now, but I'm going to assume it's a hex string.
var origCipher = "129212143036071008133136215105140171136216244116"; // is this supposed to be a hex string?
var origKey = [ 123, 217, 20, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 115, 222, 209, 241, 24, 175, 144, 175, 53, 196, 29, 24, 23, 17, 218, 131, 226, 53, 209 ];
var origIV = [ 146, 66, 191, 151, 23, 3, 113, 119, 231, 131, 133, 112, 79, 32, 114, 136 ];
var key = CryptoJS.lib.WordArray.create(new UInt8Array(origKey));
var iv = CryptoJS.lib.WordArray.create(new UInt8Array(origIV));
var cipher = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(origCipher));
var plain = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
var plaintext = CryptoJS.enc.UTF8.stringify(plain);
Above code doesn't result in a correct result, though, so your input ciphertext is probably not a hex string.
I ended up using a .net ashx generic handler, to which i post the data over ssl, and the server-side decryption takes place using the simpleAES class.
This class uses block-size as a parameter which seems to make the difference and using this approach I was able to decrypt all the strings i needed to.
More info about simpleAES here: https://github.com/huanlin/YetAnotherLibrary/blob/master/Source/Yalib/Cryptography/SimpleAes.cs
Thanks again for the help!

Javascript - Reading binary data when using chrome.devtools.network.onRequestFinished

So I am building a Chrome DevTools extension that inspects binary traffic on particular website.
Requests on site are made with responseType = "blob".
Now when I get request with chrome.devtools.network.onRequestFinished and then access its content with request.getContent(), I get string as response and not blob.
This string looks like some kind of binary string but not sure how it is encoded. I tried transforming it to base64 string with a lot of different transforms (Utf-8 to latin, Utf-16 to latin, ... ) but nothing gave correct result.
Any idea how to get correct result?
Update:
This is comparison of results (as Uint8Array) from client and extension.
Client:
[170, 69, 224, 171, 51, 233, 216, 82, 197, 35, 170, 213, 145, 197, 218, 82, 72, 85, 33, 77, 81, 88, 93, 16, 97, 234, 253, 208, 203, 221, 44, 44]
Extension:
[65533, 69, 65533, 65533, 51, 65533, 65533, 82, 65533, 35, 65533, 81, 65533, 65533, 82, 72, 85, 33, 77, 81, 88, 93, 16, 97, 65533, 65533, 65533, 65533, 65533, 44, 44]
Notice how every byte that is over 128 is converted to 65533 byte (Replacement character) in extension?
Now how can I access pure binary data?
const data = Uint8Array.from(atob(content), c => c.charCodeAt(0)) ;

Categories