CryptoPP vs PHP Base64 Encoding/Decoding - php

I am trying to create a communication exchange between an application in PHP and C++ (CryptoPP).
I have the following code in PHP:
$in = "ALApfWG920ZFle/2r6CkXKXt+zG5tiw7Gw9ZLl1mKRNP9fyb12T92e9rTQF4JeapXSrZVBPyrGx52l4zmu+wr3u2EQW7CeYFbl9h8y5+xx0MPOL/1nyX6ENzo755klTy5AxcM9GMrpKt689i79ouuxceA2bCa0cpWMUv4c2dHN8nKaXDSyCW04dRglFds9CVb29JgQamFRc7H8yjPPdk/FIMDt3xCDOKjoT5VGM1v1Tsyo92qCSFW9N4xXqLr5NUO0hv5u+kVCg0P/gWbgSSNsflXjyqV+dBp3YzKdxHGQXbpl8IQvec95GjL60zQ7IS/rWOZg40+IrwbhvoWHUQIkM="
$out = base64_decode($decode)
It decodes the text and returns a binary string, as expected.
I am doing a similar command using CryptoPP in C++:
string out;
string in = "ALApfWG920ZFle/2r6CkXKXt+zG5tiw7Gw9ZLl1mKRNP9fyb12T92e9rTQF4JeapXSrZVBPyrGx52l4zmu+wr3u2EQW7CeYFbl9h8y5+xx0MPOL/1nyX6ENzo755klTy5AxcM9GMrpKt689i79ouuxceA2bCa0cpWMUv4c2dHN8nKaXDSyCW04dRglFds9CVb29JgQamFRc7H8yjPPdk/FIMDt3xCDOKjoT5VGM1v1Tsyo92qCSFW9N4xXqLr5NUO0hv5u+kVCg0P/gWbgSSNsflXjyqV+dBp3YzKdxHGQXbpl8IQvec95GjL60zQ7IS/rWOZg40+IrwbhvoWHUQIkM=";
CryptoPP::StringSource decryptor(in, true,
new CryptoPP::Base64Decoder(
new CryptoPP::StringSink(out)
));
However, when I inspect the out string, it is empty.
Could someone please pin-point what I am doing wrong?

You cannot see the binary data because they start with a zero (\0).
\0 terminates a string, so you cannot see anything, but your data is stored.
Check:
out.size()
You can access your data with:
const char* data = out.c_str();
char* firstByte = data[0];

Related

Binary Data from PHP to Angular 6 via http

the goal is to make a http request (empty) from Angular 7 to PHP to receive binary data in Angular for the use with protobuf3.
More specifically, the binary data (encoded like described here: https://developers.google.com/protocol-buffers/docs/encoding) in PHP (source) is encapsulated in a string, while the goal in Angular is a Uint8Array.
Therefore, I currently have the following working code:
PHP Code (a simple ProcessWire root template):
header('Content-Type: application/b64-protobuf');
…
echo base64_encode($response->serializeToString());
Angular:
let res = this.httpClient.get(`${this.API_URL}`, { responseType: 'text' });
res.subscribe((data) => {
let binary_string = atob(data);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
let parsedResponse = pb.Response.deserializeBinary(bytes)
})
As you can see I encode the data as base64 before sending it. So, it is not as efficient as it could be, because base64 reduces the amount of information per character. I tried already quite a lot to get binary transmission working, but in the end the data always gets corrupted, i.e. the variable bytes is not identical to the argument of base64_encode.
But still, according to some sources (e.g. PHP write binary response, Binary data corrupted from php to AS3 via http (nobody says it would not be possible)) it should be possible.
So my question is: What must change to directly transfer binary data? Is it even possible?
What have I tried?
using different headers, such as
header('Content-Type:binary/octet-stream;'); or using Blob in Angular.
I also tried to remove base64_encode from the PHP Code and atob
from the Angular Code. The result: the content of the data is modified between serializeToString and deserializeBinary(bytes), which is not desired.
I checked for possible characters before <?php
Specifications:
PHP 7.2.11
Apache 2.4.35
Angular 7.0.2
If further information is needed, just let me know in the comments. I am eager to provide it. Thanks.

base64 decoding works differently in node than in php, perl or python

I need to decode a base64 token for an authentication string, and I found some working examples in Python, Perl and PHP, and I wrote the equivalent code in Node, but I ran into an issue. It seems the base64 decoder for Node doesn't work the same way as for the other 3 languages.
Running this in Python
token = 'BaSe64sTRiNghERe'
decoded_token = token.decode('base64')
print decoded_token
returns this string
???F#`?D^
Running this in Perl
my $token = 'BaSe64sTRiNghERe';
my $decoded_token = decode_base64($token);
print $decoded_token;
returns this string
???F#`?D^
Running this in PHP
$token = 'BaSe64sTRiNghERe';
$decoded_token = base64_decode($token, true);
echo $decoded_token;
returns this string
???F#`?D^
and finally, running this in a Node script
var token = 'BaSe64sTRiNghERe',
decoded_token = Buffer.from(token, 'base64').toString();
console.log(decoded_token);
returns this string
????F#`?D^
The question is, why the extra question mark in the decoded string? And how can I get the same result in Node as I get in Perl, Python and PHP?
UPDATE
running this in the command line
echo BaSe64sTRiNghERe | base64 --decode
gives me the same output as the perl, python and php scripts
but running the same command from node
var exec = require('child_process').exec;
exec('echo BaSe64sTRiNghERe | base64 --decode', function callback(error, stdout, stderr){
console.log(stdout);
});
I still get the wrong stuff.
The output is different since you have generated unprintable characters, and node seems to handle those unprintable characters differently from the other languages. You are also losing information:
>>> token = 'BaSe64sTRiNghERe'
>>> decoded_token = token.decode('base64')
>>> print decoded_token
???F#`?D^
>>> decoded_token[0] == decoded_token[1]
False
If you modify your python snippet to look like this:
import binascii
token = 'BaSe64sTRiNghERe'
decoded_token = binascii.hexlify(token.decode('base64'))
print(decoded_token)
Then modify your nodejs snippet to look like this:
var token = 'BaSe64sTRiNghERe',
decoded_token = Buffer.from(token, 'base64').toString('hex');
console.log(decoded_token);
You will avoid the differences in how they handle unprintable characters and see that the base64 decodes have the same byte values.

NodeJS returns other binary result from HMAC than php

I'm running node.js and php on windows and I use the included crypto module in node.js.
Php script:
hash_hmac("sha256", "foo", "bar", true) // the true enables binary output
outputs:
¶y3!è¬╝♂ï►ó│Ñ├Fä╚┘CA╝±G6▄rp¸t↑Q
Node.js script:
crypto.createHmac("sha256", "bar").update("foo").digest("binary");
outputs:
¶y3!?ª¼♂?►¢³¥ÃF?ÈÙCA¼ñG6Ürp÷t↑Q
I also wonder why some digits are the same but some others not.
I also tried getting the hex instead of the binary result, both of them output the same.
hash_hmac("sha256", "foo", "bar", false); // false outputs hex data
crypto.createHmac("sha256", "bar").update("foo").digest("hex"); // notice "hex"
This was not a solution because I failed to convert the hex data to binary:
var hmac = crypto.createHmac("sha256", "bar").update("foo").digest("hex");
var binary = new Buffer(hmac, "hex");
The variable binary outputs:
¶y3!???♂?►????F???CA??G6?rp?t↑Q
I came across the same problem when implementing a node js solution for OTP simplepay.
PHP Code:
base64_encode(hash_hmac('SHA384', $text, trim($key), true));
JS CODE:
function get_hash(key, text) {
const crypto = require("crypto");
const algorithm = "sha384";
var hmac = crypto.createHmac(algorithm, key).update(text);
return hmac.digest().toString('base64');
}
So both logged out / echoed - give the same result.
In your case, the binary output thus would be:
crypto.createHmac("sha256", "bar").update("foo").digest().toString('binary');
However, keep in mind that logging and echoing a binary string will give a slightly different view due to character encoding. You can see the same, but also different characters.
PHP echo
,cAW'B��o��傱�#�Vlάf�R#y�,?0�^1=Y�����u2
and
NODE console.log
,cAW'BÛåoº°å±¹#VlάfÞ꧸§u2
Are actually the same, they just look different.
see this github issue and addaleax's comment
calculateHmac(payload) {
const hmac = crypto.createHmac('sha256', KEY);
hmac.update(Buffer.from(payload).toString());
let bin = hmac.digest();
return Buffer.from(bin).toString('base64');
}

Equivalent PHP GZIP Compression like in VB.NET

I'm migrating a web service that was developed in VB.NET to PHP
I explain:
In VB. NET I have a method that compresses a single string with GZIP. ("Hello world!")
The method in the web service returns an array of bytes.
Then the array of bytes is received on a device with android, decompressed and converted to a string, this process works perfect.
the method in VB.NET, is this:
<WebMethod(Description:="GZIP Test")> _
Public Function GZIP() As Byte()
Dim vTest As String = "Hello world!"
Dim vBuffer1() As Byte = StrToByteArray(vTest)
Dim vBuffer2() As Byte = Compress(vBuffer1)
Return vBuffer2
End Function
Private Function StrToByteArray(ByVal str As String) As Byte()
Dim encoding As New System.Text.UTF8Encoding()
Return encoding.GetBytes(str)
End Function
Private Function Compress(ByVal Bits() As Byte) As Byte()
On Error Resume Next
Using ms As New MemoryStream(), zipMem As New GZipStream(ms, CompressionMode.Compress, True)
zipMem.Write(Bits, 0, Bits.Length)
zipMem.Close()
Return ms.ToArray
End Using
End Function
this method returns me the following value:
<base64Binary>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ir6dl2WVXlV1Oftd/x+VGYUbDAAAAA==</base64Binary>
I want PHP return me the SAME VALUE.
the tests I've done in PHP returns me the following.
function GZIP() {
ob_start ( 'ob_gzhandler' );
return base64_encode(gzdeflate('Hello world!', 9));
}
the value returned in PHP is:
80jNyclXKM8vyklRBAA=
Why ? There is an example that returns the same ?
Thanks in advance for all.
You are using the wrong de-/compression algorithm. Use phps gzcompress() and gzuncompress() instead.
First off, you can't require the exact same result. All you can require of a lossless compressor is that it reproduce exactly the same input when decompressed.
Second, you want to use gzencode to produce gzip streams. Neither gzdeflate nor gzcompress will do that. The former produces raw deflate streams, and the second zlib streams. (Don't get me started about the misleading names and the messed up PHP documentation about them.)

How do I get the complete string of a BLOB using PDO?

I'm creating a C# to PHP Data Connector to allow for a standardized connection to a web server to host data from a database to a C# WinForm application. Everything is working with this one small exception.
The basic of use is this.
C# sends an AES encrypted command to the server. The server parses the command and performs the SQL query and returns an AES encrypted string. This string is then converted to a DataTable in C#.
When the SQL contains a column that is a BLOB I'm only getting back a small part of the full data. It seems that the field is being limited to only the first 2792 bytes.
Is there a setting that is preventing the full contents of the BLOB to be returned?
I'm not sure if it will be helpful, but here is the code that does the work.
$DataConnection = new PDO('mysql:host=10.10.100.102;dbname=jmadata', "root", "nbtis01");
$DataConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (isset($Parameters['SQLQuery'])) { // Default List
$SQLQuery = $Parameters['SQLQuery'];
unset($Parameters['SQLQuery']);
}
if (isset($Parameters['LimitOverride'])) {
if (!strpos(strtoupper($SQLQuery), "LIMIT"))
$SQLQuery = rtrim($SQLQuery, ';') . " LIMIT " . $Parameters['LimitOverride'];
unset($Parameters['LimitOverride']);
}
$QueryParams = array();
foreach ($Parameters as $key => $value)
if ($key !== '')
$QueryParams[$key] = $value;
$Query = $DataConnection->prepare($SQLQuery);
$Query->execute($QueryParams);
$ReturnArray = $Query->fetchAll(PDO::FETCH_ASSOC);
if (!$ReturnArray)
$ReturnArray[0] = array("NoResults" => "");
EDIT -- ANSWER
I found my issue. The problem had nothing to do with PDO, PHP or MySQL. I was taking the BLOB data and doing a Base64 to it before putting it in the array, as the split characters I was using to build the result string that would be converted to datatable in c# used non-printable characters and the binary data as a string might have included these characters. The issue was when I was doing a convert in c# to get the original string so that could convert that to a byte array. I was using System.Text.Encoding.ASCII.GetString to convert the Base64 byte array to the original string. This was working on everything but the binary data from the BLOB fields.
The suggestion that it might be a terminating character is what made me find it. Once the Base64 was converted to string using ASCII there was something that was turning into a terminator and it was stopping the convert at that point. Once I found this I changed to System.Text.Encoding.Default.GetString and now it works perfect.
Posted the answer in case anyone else might be trying to do this and having this same issue.
More details in the Edit of the question.
Changed from System.Text.Encoding.ASCII.GetString to System.Text.Encoding.Default.GetString and the issue was resolved.
Thank you crush for pointing me in the right direction to find the solution.

Categories