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
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 ... :/