How to get the same result with PHP and CryptoJS using SHA256? - javascript

I'm trying to decode Firefox Sync data using javascript, porting one php library which does it (https://github.com/mikerowehl/firefox-sync-client-php). The idea is to decode sync data without sending sync key to the server. This is just context, the problem I have is much more specific.
One portion of code requires using sha256 to obtain certain key. I would like to replicate it in javascript. The approach I've tried, with CryptoJS, is this:
PHP code:
$key = hash_hmac("sha256",'OLA K ASE','CLAVE', false);
print $key;
Equivalent Javascript code (previously, I've included http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js):
var hash = CryptoJS.HmacSHA256("OLA K ASE", "CLAVE");
console.log(hash.toString());
This works fine. In each case, output is 9591d44df0c8e2d7a1f400f41117c536e10f58d7e28bdc1cad9d81e70290bc1b, which I suppose is correct.
But, when I'm trying to encode non-ascii strings, results differ. For example, with this PHP code:
function hexstring($str){
return preg_replace('/\\\\x([0-9a-f]{2})/e', 'chr(hexdec(\'$1\'))', $str);
}
$text = hexstring('\x00\x44\xb0\x2c\x0b');
$key = hexstring('\xd6\xf8\xb0\x2c\x0b');
$hash = hash_hmac("sha256",$text,$key, false);
print $hash;
I get 0697f5528c996006ffeb09b9130bf8e9056563245656d405e233bcafdbffb645. But with the 'equivalent' javascript code:
var text = "\x00\x44\xb0\x2c\x0b";
var key = "\xd6\xf8\xb0\x2c\x0b";
hash = CryptoJS.HmacSHA256(text,key);
console.log(hash.toString());
I get 13c983b69f82c277815c03d13e90b1ec1e9cbca2b6912ad1f8224f3de8b82130, a different value.
I thought it could be caused by non-ascii character, so I did a quick test:
$text = '';
for($i = 0;$i < 10; $i++){
$text .= chr($i);
}
$key = '';
for($i = 0;$i < 10; $i++){
$key .= chr($i*2);
}
$hash = hash_hmac("sha256",$text,$key, false);
print $hash;
And, javascript equivalent:
var text = '';
for(i = 0;i < 10; i++){
text += String.fromCharCode(i);
}
var key = '';
for(i = 0;i < 10; i++){
key += String.fromCharCode(i*2);
}
var hash = CryptoJS.HmacSHA256(text, key);
console.log(hash.toString());
In both cases, output is c5d7adbbabcec5416c6b7a1f01e17e42d95a529f5bcc805d9b04b93f33994c9d.
This is a big WTF? for me. Could somebody give me a piece of advice of how to continue with this?

Solved. It was a problem with character codes. Instead of this:
var text = "\x00\x44\xb0\x2c\x0b";
var key = "\xd6\xf8\xb0\x2c\x0b";
hash = CryptoJS.HmacSHA256(text,key);
I should indicate CryptoJS that they were Latin-1 encoded strings:
var text = CryptoJS.enc.Latin1.parse("\x00\x44\xb0\x2c\x0b");
var key = CryptoJS.enc.Latin1.parse("\xd6\xf8\xb0\x2c\x0b");
hash = CryptoJS.HmacSHA256(text,key);
I don't know clearly why is this happening, so if somebody could explain it with a little bit of detail it would be great.

Try that:
$text = "\x00\x44\xb0\x2c\x0b";
$key = "\xd6\xf8\xb0\x2c\x0b";
$hash = hash_hmac("sha256",$text,$key, false);
print $hash;
It's proabably because the preg_* functions have a problem with these special characters.
And PHP supports \x12 hex-encoding without any function.

Related

Get signature values from PDF (PHP+JS)

How I can get values (date, signing name etc.) from sign('s) inside PDF? At my application on Joomla and Fabrik component i can run PHP and JS code.
The code I am currently using from Stack is not working as expected. If I read on browser $content variable, i cannot see /ByteRange, but when i take it to txt file, there is. On my XAMPP instance i have installed Composer and ASN1 and X509 libraries.
For all, this is my code with some changes for take content form file (I thought maybe it would work, but it doesnt) :
<?php
require_once('C:\Windows\System32\vendor\autoload.php');
use Sop\ASN1\Type\Constructed\Sequence;
use Sop\ASN1\Element;
use Sop\X509\Certificate\Certificate;
$currentFile = 'C:\xampp\htdocs\ArchiTW\upload\kprocajlo\dokumenty\test.pdf';
$content = file_get_contents($currentFile);
file_put_contents('C:\xampp\htdocs\ArchiTW\upload\kprocajlo\dokumenty\text.txt',$content);
$txt='C:\xampp\htdocs\ArchiTW\upload\kprocajlo\dokumenty\text.txt';
$regexp = '/ByteRange\ \[\s*(\d+) (\d+) (\d+)/'; // subexpressions are used to extract b and c
//$regexp = '#ByteRange\s*\[(\d+) (\d+) (\d+)#';
$result = [];
$abc=preg_match_all($regexp, $txt, $result);
//$result[2][0] and $result[3][0] are b and c
if (isset($result[2]) && isset($result[3]) && isset($result[2][0]) && isset($result[3][0])) {
$start = $result[2][0];
$end = $result[3][0];
if ($stream = fopen($currentFile, 'rb')) {
$signature = stream_get_contents($stream, $end - $start - 2, $start + 1); // because we need to exclude < and > from start and end
fclose($stream);
}
$binaryData = hex2bin($signature);
$seq = Sequence::fromDER($binaryData);
$signed_data = $seq->getTagged(0)->asExplicit()->asSequence();
// ExtendedCertificatesAndCertificates: https://tools.ietf.org/html/rfc2315#section-6.6
$ecac = $signed_data->getTagged(0)->asImplicit(Element::TYPE_SET)->asSet();
// ExtendedCertificateOrCertificate: https://tools.ietf.org/html/rfc2315#section-6.5
$ecoc = $ecac->at($ecac->count() - 1);
$cert = Certificate::fromASN1($ecoc->asSequence());
$commonNameValue = $cert->tbsCertificate()->subject()->toString();
$StatusMsg = $commonNameValue;
echo $commonNameValue;
}

AJAX returning a white space from PHP echo

This is a problem I been having several times, and I always ignore because I cant find a solution.
Basically every time I echoed a value back to Javascript using AJAX, the first value will contain a space (extra character) this is annoying because if I want to check if that value exist sometimes I cant due to the space.
Normally the values returned is something like this
Value1
Value2
Value3
Here is the code below. I suggest to ignore the function seperate_ajx_data as I dont think the problem is located there.
results[0] is giving a white space plus the value!
What could be the issue of having a space in the first value?
PHP code:
$machine = null;
$sql = mysqli_query($connection, "SELECT......");
while($row = mysqli_fetch_array($sql)){
$machine .= $row['MACHINE']."+";
$machine .= $row['COUNT(MACHINE)']."/";
}
echo $machine;
JavaScript code:
function get_machine_vals(id){
var ht = new XMLHttpRequest();
var url = "....";
var val = "....="+id;
ht.open("POST", url, true);
ht.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ht.onreadystatechange = function(){
if(ht.readyState == 4 && ht.status == 200){
var val = ht.responseText;
var results = seperate_ajx_data(["/","+"],val);
var el = document.getElementById("machine_dropdown");
var opts = el.options;
for(var i =0;i<results.length;i++){
var tmp = results[i];
alert(tmp + " " + tmp.length);
switch (results[i]){
case "Test":
opts[0].innerHTML = "Seko "+results[i+1];
break;
}
}
}
};
ht.send(val);
}
function seperate_ajx_data(symbols, val){
var tmp_storage = [];
var tmp_spliter = val.split(symbols[0]);
var results = [];
for(var x = 0;x<tmp_spliter.length;x++){
tmp_storage = tmp_spliter[x].split(symbols[1]);
for(var y = 0;y<tmp_storage.length;y++){
results.push(tmp_storage[y]);
}
}
return results;
}
This is unfortunately one of those "gotchas" when working with PHP. The errant character might come from a space after a closing PHP tag. A contrived example:
<?php
... do some work ...
?> <?php
... do some work, but note errant space between the tags
Possible fixes?
Don't close the PHP tag
Use a different transfer mechanism that is space-tolerant, for example JSON or XML.
Strip (or "trim") your values client side. In context of your code:
var val = (ht.responseText || '').trim();
Just check your opening <?php brackets, there might be a space (i've seen this before).
It happened with me today. And unlike other answers related to opening bracket, for me it was the space after the closing bracket.
<?php
.....
?>[space][space][space]
I removed the spaces. And solved the issue.

PHP & JS mcrypt decryption not working

I have the following code in Javascript to encrypt a string using a key:
des.js is this: http://www.tero.co.uk/des/code.php
<script src="/js/des.js"></script>
<script>
var key = '12345678';
var message = 'hello world';
var ciph = des(key, message, 1, 0);
ciph = stringToHex(ciph);
console.log("Encrypted Result: " + ciph);
</script>
Then I send it server side and attempt to decrypt with this PHP code:
$key = '12345678';
$hexa = '0x28dba02eb5f6dd476042daebfa59687a'; /This is the output from Javascript
$string = '';
for ($i=0; $i < strlen($hexa)-1; $i+=2) {
$string .= chr(hexdec($hexa[$i].$hexa[$i+1])); }
echo mcrypt_decrypt(MCRYPT_DES, $key, $string, MCRYPT_MODE_ECB);
Ive tried converting it to utf8, changing encoding, changing the hex decoding, etc, but it always comes out gibberish, sometimes as nonreadable characters, other times as readable but nonsense.
The way to decrypt the string is not working properly, try this:
$key = '12345678';
$hexa = '0x28dba02eb5f6dd476042daebfa59687a';
function hexToString ($h) {
$r = "";
for ($i= (substr($h, 0, 2)=="0x")?2:0; $i<strlen($h); $i+=2) {$r .= chr (base_convert (substr ($h, $i, 2), 16, 10));}
return $r;
}
echo mcrypt_decrypt(MCRYPT_DES, $key,hexToString('0x28dba02eb5f6dd476042daebfa59687a'), MCRYPT_MODE_ECB);
The output will be: hello world
This way work properly, however, you should search another method to encrypt your data, in your script the key (12345678) and your encrypt method is visible to everyone.
Data to be encrypted with a block cipher such as DES or AES must be an exact multiple of the block size in length. The solution is to add padding to the data to be encrypted, PKCS#5 padding is the usual padding for DES and probably the default for Javascript. Unfortunately mcrypt does not support PKCS#5 padding, only a non-standard zero padding.
Potential solutions:
Use a better encryption function than mcrypt, see the comment to the question.
Specify no padding in Javascript and manually add zero padding.
Specify no padding in mcrypt and remove the padding manually.
It is better tospecify all options and no to rely on defaults.

Javascript encryption that match with PHP decryption [duplicate]

This question already has answers here:
Encrypt with CryptoJS and decrypt with PHP
(3 answers)
Closed 6 years ago.
I have the php code as below, and I want to create a Javascript functions that work the same as the php code below. Also, the data that encrypted in Javascript can also decrypt in php.
`
<?php
class Security {
public static function encrypt($input, $key) {
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$input = Security::pkcs5_pad($input, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode($data);
return $data;
}
private static function pkcs5_pad ($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
public static function decrypt($sStr, $sKey) {
$decrypted= mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$sKey,
base64_decode($sStr),
MCRYPT_MODE_ECB
);
$dec_s = strlen($decrypted);
$padding = ord($decrypted[$dec_s-1]);
$decrypted = substr($decrypted, 0, -$padding);
return $decrypted;
}
}
?>
`
Use crypto.js at javascript end. Reference over here
Javascript
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
/*
if you wish to have a more friendly key, you can convert letters to Hex this way:
var a = "D";
var hex_D = a.charCodeAt(0).toString(16);
just to mention,
if it were to binary, it would be:
var binary_D = a.charCodeAt(0).toString(2);
*/
var secret = "secret key goes here";
//crypted
var encrypted = CryptoJS.AES.encrypt(secret, key, {iv : iv});
//and the ciphertext put to base64
encrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
//Assuming you have control on the server side, and know the key and iv hexes(we do),
//the encrypted var is all you need to pass through ajax,
//Let's follow with welcomed pure JS style, to reinforce one and other concept if needed
var xh = new XMLHttpRequest();
xh.open("POST", "php.php", true);
xh.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xh.send("encrypted=" + encodeURIComponent(encrypted));
xh.onreadystatechange = function() {
if (xh.readyState == 4 && xh.status == 200) {
var myArr = (xh.responseText);
console.log(myArr);
}
};
At PHP
<?php
//Here we have the key and iv which we know, because we have just chosen them on the JS,
//the pack acts just like the parse Hex from JS
$key = pack("H*", "0123456789abcdef0123456789abcdef");
$iv = pack("H*", "abcdef9876543210abcdef9876543210");
//Now we receive the encrypted from the post, we should decode it from base64,
$encrypted = base64_decode($_POST["encrypted"]);
$shown = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
echo trim($shown);
//Although the decrypted is shown, there may be needed to trim and str_replace some \r \n \x06 \x05, if there is not a better "trim" way to do it though
?>
You can use JXG compressor too

Printing JavaScript escaped string safely in php

I am using encodeURIComponent() (and encodeURI() for e-mails) to take inputs safely from the user, and am then sending the output to php via ajax. The php processes it and puts this escaped sting into a $_SESSION[] which I then to to echo later. I was wondering if it was possible to print this to html normally, and then have html ignore anything inside it being code (e.g. would be treated as text instead of a tag) or even combine these two steps. I think the format for JavaScript encoding is different than that of php, so this might be an issue, but if it is, what would be the best way to change these stings in php (I'm storing these escaped strings in MySQL)?
Thanks in advance.
Theese are the functions I use when I handle strings from users in php.
save is for save to database,
edit is editing in input/textareas
show is to write it out showing the tags as text in html.
// SAVE DATA
function save($str)
{
return mysql_real_escape_string($str);
}
//############################################################################
// EDIT DATA
function edit($str)
{
$patterns[0] = '/</';
$patterns[1] = '/>/';
$patterns[2] = '/"/';
$patterns[3] = "/'/";
$replacements[0] = '<';
$replacements[1] = '>';
$replacements[2] = '"';
$replacements[3] = ''';
$str = preg_replace($patterns, $replacements, $str);
$str = trim($str);
return stripslashes(stripslashes(str_replace('\r\n', '
', $str)));
}
//############################################################################
// SHOW DATA
function show($str)
{
$patterns[0] = '/</';
$patterns[1] = '/>/';
$patterns[2] = '/"/';
$patterns[3] = "/'/";
$replacements[0] = '<';
$replacements[1] = '>';
$replacements[2] = '"';
$replacements[3] = ''';
$str = preg_replace($patterns, $replacements, $str);
$str = trim($str);
return stripslashes(stripslashes(str_replace('
', '<br />', $str)));
}
play around with it and see if it works for you :)

Categories