Hello,
We are trying to implement some actions using the REST API, in a Java application.
This works fine for GET actions, but fails for PUT or POST.
We seem to have a problem with the implementation of the AES-CTR encryption / decryption : the Java library expects an IV (Initialization Vector) parameter in the encryption function, but there doesn't seem to be such a parameter in the PHP-AES version.
Do you know how we should set this IV parameter ? (tried setting it to NULL without success)
Code used is attached below.
Cheers
And this is the problem I think many persons reported on the forum. Projeqtor uses PHP library for AES:CTR create by Chris Veness ( https://www.movable-type.co.uk/scripts/aes.html). This library uses it's own implementation of AES CTR and generate VI (key) base on password passed to function. Problem is this VI (key) is generated in a little complicated way.
I tried to connect C# to Projeqtor API and point was (probably like you and many others) how to encrypt data in C# using AES CTR. To do this you need to know VI key.
Take a look for projeqtor source code - you can find like like this:
$data=AesCtr::decrypt($dataEncoded, $user->apiKey, Parameter::getGlobalParameter('aesKeyLength'));
As you can see data you send to projeqtor via api are decrypted using function AesCtr:decrypt (from library I mentioned above) and as secret user_api_key is used. There is nowere passed VI key which we are looking for. Again this VI key is generated from user_api_key.
What is inside AesCtr:decrypt:
public static function encrypt($plaintext, $password, $nBits)
{
$blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) return ''; // standard allows 128/192/256 bit keys
// note PHP (5) gives us plaintext and password in UTF8 encoding!
// use AES itself to encrypt password to get cipher key (using plain password as source for
// key expansion) - gives us well encrypted key
$nBytes = $nBits / 8; // no bytes in key
$pwBytes = array();
for ($i = 0; $i < $nBytes; $i++) $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
$key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
$key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
....
So as you see generally user_api_key (used as secret) is expanded and itself again ecrypted by AES. A little complicated to implemenet outside projeqtor.
Unless my analysis is wrong, projeqtor should use something standard (standard for whole world not PHP only).
Hello kobetsu,
I'm trying to write an interface with C# and face the same problem.
Did you finally found a workarround or do you have a C# code sample that works?
I'm stuck there, and I would avoid to wrap and PHP call from my C# program...
We extended API of PQ by method allowing us to encrypt passed text. It was the easiest way for us.
Thank you for your answer.
I wonder if I will get in the same direction.
I would have prefered to stay unchanged PQ code, but the way the Encrypt function works is making me mad!
I'm running this PHP code from my C# program :
[code=php]
It update my file from
[code=json]{"id":"1","figgoId":"5"}
To some crypted phrase :
cQJXBgVIBWLhCDG90KlyKw7zZ5093Yjunso75kwBSUPATK8=
Then I send it to the API :
[code=csharp]
var formContent = new FormUrlEncodedContent(new
{
new KeyValuePair;("data", crypted)
});
Console.WriteLine($"Donnée brute : {data}");
Console.WriteLine($"Donnée chiffrée : {crypted}");
HttpResponseMessage msg = await client.PostAsync(string.Concat(url, User.PATH), formContent);
Console.WriteLine(await msg.Content.ReadAsStringAsync());
But still always get this :
Donnée brute : {"id":"11", "figgoId":"30"}
Donnée chiffrée : cQJXBgVIBWLhCDG90KlyKw7zZ5093Yjunso75kwBSUPATK8=
{"error":"invalid API query", "message":""'data' is not correctly encoded for method PUT. Request for correct API KEY""}
Thus when I run several times the same input message I get different encrpyted data, so I really wonder how the server would be able to decrypt it back as it changes other time...
1.
I see you declared encryption 256 by line:
$data = AesCtr::encrypt($contents, $_SERVER['argv'][1], 256);
Are you sure your PQ is using 256 ? not 128 ?
2.
Use this code as example:
string strURI = "https://xxxx/api/Delivery";
//"{"id":"1090","name":"test"}";
strData = "XgEJZxQhrmHmPqjzqQ9YdgljeYiBAri7Y73i192XSZFLG8w"; //<--- here put your encrypted string
var content = new StringContent(strData, Encoding.UTF8, "application/json");
HttpClient httpClient = new HttpClient();
httpClient .DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{<>}:{<>}")));
var result = httpClient.PutAsync(strURI, content).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
Thank you, you're right, the problem was just about the 256.
With 128 bits it works now!
I was simply following this documentation that uses 256:
https://www.projeqtor.org/media/kunena/attachments/5188/ProjeQtOr.pdf#:~:text=ProjeQtOr%20provides%20an%20API%20to%20interact%20with%20its,security%20reasons%20it%20is%20not%20enabled%20by%20default.
Donnée brute : {"id":"7", "figgoId":"8"}
Donnée chiffrée : VQDiWUxpBWLaiLih2Vbr9W/PaF+n8xRVGcJHfflgj9lb
{"identifier":"id", "items":[{"apiResult":"OK", "apiResultMessage":"Ressource #7 mis à jour", "id":"7", "figgoId":"8", [...] }] }