View ProjeQtOr On SourceForge.net
ProjeQtOr - Project Management Tool
Support us on Capterra
OIN - Open Invention Network
ProjeQtOr free project management software - API & Encryption - ProjeQtOr
 
 

API & Encryption

More
04 Jan 2021 16:47 - 04 Jan 2021 16:57 #1 by fsouliers
API & Encryption was created by fsouliers
Hello all and happy new year !

I had troubles with the API system, particularly regarding the encryption system. It follows this previous locked discussion : www.projeqtor.org/fr/forum-fr/5-ask-ques...on-connection-to-api

I have the same problem as Xav38 : the API works perfectly if I bypass the decryption system in the "if" block line 269 of api/index.php, replacing the
$data=AesCtr::decrypt ...
with a dirty
$data=$dataEncoded ;

Just for information, here is the python script :
import pycurl

from io import BytesIO

import ast

from Crypto.Cipher

import AES

import binascii

from base64 import b64encode, b64decode

import json 

login="admin.api"

key="d87b5ca7c5fdf827aa35914e966bf768"  

##################### Reading test###################

buffer = BytesIO()

c_getProj = pycurl.Curl()

c_getProj.setopt(c_getProj.URL, 'http://localhost/projeqtor/api/Project/all')

c_getProj.setopt(c_getProj.HTTPAUTH , pycurl.HTTPAUTH_BASIC)

c_getProj.setopt(c_getProj.USERPWD , "%s:%s"%(login,key))

#c_getProj.setopt(c_getProj.SSL_VERIFYPEER, False)

c_getProj.setopt(pycurl.WRITEDATA, buffer) 

c_getProj.perform()

c_getProj.close() 

body = ast.literal_eval(buffer.getvalue().decode("UTF-8")) 

# Juste pour simuler une sélection

projetRetenu = [x for x in body["items"] if x["nameStatus"] == 'qualified'][0]

print (projetRetenu)

 

##################### Writing test###################

# Définition d’une activité à créer

activite = {"name" : "Activité de test","idActivityType" : "26","idProject" : projetRetenu["id"],"idStatus" : "1","idResource" : "3","creationDate" : "2020-12-24",'idActivityPlanningMode': '1'} 

c_setAct = pycurl.Curl()

c_setAct.setopt(c_setAct.URL, 'http://localhost/projeqtor/api/Activity')

c_setAct.setopt(c_setAct.HTTPAUTH , pycurl.HTTPAUTH_BASIC)

c_setAct.setopt(c_setAct.USERPWD , "%s:%s"%(login,key)) 

res = json.dumps(activite)

c_setAct.setopt(c_setAct.CUSTOMREQUEST, "POST")

c_setAct.setopt(c_setAct.POSTFIELDS, res)

c_setAct.perform()

c_setAct.close()


In that case, I can see the succesful result in the logs :
===== TRACE ===== {"apiResult":"OK", "apiResultMessage":"Activité #432 inséré", "id":"432", "reference":"-TAS-40", "name":"Activité de test", "idActivityType":"26", ...



Now, regarding the encryption, I use pycryptodome and I use it with several other encrypted APIs not written in python ... and it works, so I consider this library as reliable (at least in a first approach).
Here is the writing test part of the script to test encryption / decryption (replacing previous one) :
##################### Writing test###################

# Définition d’une activité à créer

activite = {"name" : "Activité de test","idActivityType" : "26","idProject" : projetRetenu["id"],"idStatus" : "1","idResource" : "3","creationDate" : "2020-12-24",'idActivityPlanningMode': '1'}  

c_setAct = pycurl.Curl()

c_setAct.setopt(c_setAct.URL, 'http://localhost/projeqtor/api/Activity')

c_setAct.setopt(c_setAct.HTTPAUTH , pycurl.HTTPAUTH_BASIC)

c_setAct.setopt(c_setAct.USERPWD , "%s:%s"%(login,key)) 

print("-----------------------------------")

res = json.dumps(activite)

print("Chaine json : " + res) 

key_b=binascii.a2b_hex(key)

cipher = AES.new(key_b, AES.MODE_CTR, nonce=binascii.a2b_hex("CAFEBEEFCAFEBEEF")) # Forced 8 bytes nonce as this is the expected size on server side

ct_bytes = cipher.encrypt(res.encode("utf-8"))

ciphertext = b64encode(cipher.nonce + ct_bytes)

print("Texte encrypté : " + str(ciphertext))

print("Texte b64decode :" + str(b64decode(ciphertext))) 

c_setAct.setopt(c_setAct.CUSTOMREQUEST, "POST")

c_setAct.setopt(c_setAct.POSTFIELDS, ciphertext)

c_setAct.perform()

c_setAct.close() 


# just to test local decryption

tmp = b64decode(ciphertext)

cipher_d = AES.new(key_b, AES.MODE_CTR, nonce=tmp[:8])

msg_d = cipher_d.decrypt(tmp[8:])

print("Texte décrypté : " + str(msg_d))

The output is (I added return lines) :
-----------------------------------
Chaine json : {"name": "Activit\u00e9 de test", "idActivityType": "26", "idProject": "2", "idStatus": "1", "idResource": "3", "creationDate": "2020-12-24", "idActivityPlanningMode": "1"}


Texte encrypté : b'yv6+78r+vu/Z4Ln+J0/Ke0pUDZrbrQHKtql/wxi3ZESJGDQk/fm09NN270CSpUmIsQ/cwjUT1U+5FdwSBcCreT/uNyVS13N1WqmWMtg1UjNsfjrgiD7DF5A+K6iqv9CMUeHQOheczLbtz+XQjC/ZUXCc+uVOagwrX1R2WoPjrqd1yERIOEFr8v/omdf1LIeSVeocqPP2JexfSZ957uK9tCaECluEBekBizAGU4R80Q2evlG9'


Texte b64decode :b"\xca\xfe\xbe\xef\xca\xfe\xbe\xef\xd9\xe0\xb9\xfe'O\xca{JT\r\x9a\xdb\xad\x01\xca\xb6\xa9\x7f\xc3\x18\xb7dD\x89\x184$\xfd\xf9\xb4\xf4\xd3v\xef@\x92\xa5I\x88\xb1\x0f\xdc\xc25\x13\xd5O\xb9\x15\xdc\x12\x05\xc0\xaby?\xee7%R\xd7suZ\xa9\x962\xd85R3l~:\xe0\x88>\xc3\x17\x90>+\xa8\xaa\xbf\xd0\x8cQ\xe1\xd0:\x17\x9c\xcc\xb6\xed\xcf\xe5\xd0\x8c/\xd9Qp\x9c\xfa\xe5Nj\x0c+_TvZ\x83\xe3\xae\xa7u\xc8DH8Ak\xf2\xff\xe8\x99\xd7\xf5,\x87\x92U\xea\x1c\xa8\xf3\xf6%\xec_I\x9fy\xee\xe2\xbd\xb4&\x84\n[\x84\x05\xe9\x01\x8b0\x06S\x84|\xd1\r\x9e\xbeQ\xbd"


Texte décrypté : b'{"name": "Activit\\u00e9 de test", "idActivityType": "26", "idProject": "2", "idStatus": "1", "idResource": "3", "creationDate": "2020-12-24", "idActivityPlanningMode": "1"}'


On the server side, the b64 decoded string is exactly the same, the nonce is properly extracted ($ctrTxt) ... but the string is not properly decrypted :(

I had a look to external/phpAES/aesctr.class.php ... and several points let me think there might be some implementation issue : 
At the end, solving this problem seems quite time consumming and maybe a workaround could be acceptable : would it be possible to have a setting to activate / deactivate encryption for the API ?
By the way, why is the GET unencrypted ?

Any help is welcome ... :/
Last edit: 04 Jan 2021 16:57 by fsouliers.
The following user(s) said Thank You: bgenolini

Please Log in or Create an account to join the conversation.

More
04 Jan 2021 17:07 #2 by fsouliers
Replied by fsouliers on topic API & Encryption

Please Log in or Create an account to join the conversation.

More
04 Jan 2021 17:13 #3 by babynus
Replied by babynus on topic API & Encryption
data must be encrypted with AES using the API key, and default uses AES decryption with 128bits keys .
If your encryption uses other key length (256 or else), you can define $aesKeyLength in parameters.php 

Babynus
Administrator of ProjeQtOr web site

Please Log in or Create an account to join the conversation.

More
05 Jan 2021 07:44 #4 by fsouliers
Replied by fsouliers on topic API & Encryption
Hello,
I added the script to have a clearer comprehension.
The key is a 128bits, as generated for the dedicated user I created in Projeqtor (see lines 15 & 61).
Attachments:

Please Log in or Create an account to join the conversation.

More
06 Jan 2021 09:03 - 06 Jan 2021 09:04 #5 by babynus
Replied by babynus on topic API & Encryption
Hi
I don't know python, so it's a bit hard to read for me.
But I don't understand why you encode in base 64 the encrypted data.

Here is some PHP code that works (maybe AES encrption should be changed to 128)

$fullUrl="http://myserver/api/Ticket";
$data='{"id":"1", "name":"name to be changed for Ticket 1"}';
$data=AesCtr::encrypt($data, 'ApiKeyForUserProjeqtor', 256);
$curl = curl_init($fullUrl);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, "projeqtor:projeqtor");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$curl_response = curl_exec($curl);
echo $curl_response;
curl_close($curl);


Babynus
Administrator of ProjeQtOr web site
Last edit: 06 Jan 2021 09:04 by babynus.

Please Log in or Create an account to join the conversation.

More
14 Sep 2021 17:02 #6 by fsouliers
Replied by fsouliers on topic API & Encryption
Hello @babynus,
following this topic I have had an intern who developped an apiV2 using libsodium so we can have a full encryption of the data. We currently have written the php client classes and the python client classes (I am struggeling to find some time to write a C++/Qt and C# client). We fully tested it on v9.2.2 (and merged evolutions of API) and I am going to validate the upgrade in v9.2.3.
It works really well (even if some improvements will be welcome), so I was wondering if you could be interested in such a contribution? If yes, I obviously provide you all the required code, explanations and eventually some modification to better fit into the original projeqtor source code. 

Please Log in or Create an account to join the conversation.

Moderators: babynusprotion
Time to create page: 0.049 seconds

Cookies settings

×

Functional Cookies

Ce site utilise des cookies pour assurer son bon fonctionnement et ne peuvent pas être désactivés de nos systèmes. Nous ne les utilisons pas à des fins publicitaires. Si ces cookies sont bloqués, certaines parties du site ne pourront pas fonctionner.

Session

Please login to see yours activities!

Other cookies

Ce site web utilise un certain nombre de cookies pour gérer, par exemple, les sessions utilisateurs.