sio-2425/delivery3/decisions.adoc

88 lines
5.4 KiB
Plaintext

== Decisions
In this topic, it'll be presented and discussed the decisions made by the authors of the project thorough its development. These can range from choices taken to be used for encryption to the implementation of the API itself.
=== Usage of the Diffie-Hellman Key Exchange
The Diffie-Hellman key exchange is used in this project to securely create and maintain a key where both ends (client and server) know that key, but never exchange it. Diffie-Hellman is great for this, since by exchanging the parameters used to generate the key, and each other's public key, both can end up with the same key, without ever needing to exchange it on a public channel.
The key generation (public and private) is done using the parameters agreed on both ends (using the `dh` package from `cryptography`).
=== Symmetric Encryption
The symmetric encryption used in this project is AES-CFB. This is a symmetric encryption algorithm that is widely used and considered secure. This cipher was chosen due to the FeedBack functionality, that avoids the same plaintext to be encrypted to the same ciphertext, which is a vulnerability present in the ECB mode.
This type of encryption is used to encrypt anonymous requests and files. Both use an Initialization Vector (IV) of 16 bytes, with it being randomly generated.
[[decisions_authentication]]
=== Authentication
When it comes to authentication, there were multiple options to create a secure and reliable system. The chosen method was the same as the one used by ssh, which uses a key pair to authenticate the user.
The key pair is generated using the RSA algorithm, with a key size of 2048 bits. The public key is stored on the server, associated to the user, and the private key is kept privately by the user.
During the login, the client sends a login request with the username and organization, to which the server generates and returns a challenge (a string of 256 random characters). The client then signs this challenge with its private key and sends the signature back to the server. The server then verifies the signature using the public key associated with the user and, if the signature is valid, the user is authenticated and thus the session is validated.
=== File Handling
As mentioned before, the files are encrypted symmetrically. The key used to decrypt them is within its metadata, which can only be accessed with the required permissions. The encryption and decryption is done by blocks (or chunks) of 2^11^ bytes.
=== Session-Related Content
By default, all keys, files and session files are stored under `~/.sio` on the client side. In order to clear all files generated by the application, the user must run `rm -r ~/.sio/`
=== Hashing
For the hashing, it was used the SHA256 hashing mechanism, since it produces a 256 byte value. This is used to check the file integrity when going from Client → Server and vice versa.
=== Database
The authors of this project have chosen to use a database to store all server-side content (except for the files' content).
The database used in this project is SQLite3. This was chosen due to the authors' familiarity with it, its simplicity and the fact that it is a single file, which makes it easier to manage and distribute. SQLAlchemy was also used to interact with the database, as it provides a more abstract way to interact with the database and to have the ability to have the dataclasses corresponding to the tables. When needed, it can be reset using an endpoint mentioned in the link:#features[Features chapter].
=== Modularized Server
The server is modularized in order to make it easier to maintain and expand.
For this, Flask's Blueprints were used. This allows for the server to be divided into multiple modules, each with its own set of endpoints.
Each service has its own file and class, which makes it easier to understand and maintain. This also makes it easier to add new services to the server, as they can be added as new files and classes. This also allows for the endpoints to be easily changed as there are no real operations being done on them, but instead they are just calling the respective service.
=== Roles
The roles are used to define the permissions of each user. The permissions are stored, viewed and treated as seen in other services, like Discord. This approach is as follows:
[source,python]
----
class Perm(Enum):
DOC_ACL = 0b000000000001
DOC_READ = 0b000000000010
DOC_DELETE = 0b000000000100
#...
----
Since it is stored in bits, validating a permission or adding it to a role is very easy, since it'll be just bit-wise operations.
==== Checking a permission
To check if a role has a permission, it can be easily done by looking at the bit corresponding to the permission, and do a simple AND operation with said bit (that bit has to be 1). For this, the following function was created:
[source,python]
----
def check_perm(bit_array: int, perm_to_check: int) -> bool:
return bit_array & perm_to_check == perm_to_check
----
==== Changing a permission
To change a permission associated with a role, all that is needed is a OR operator (to add) or a AND operator (to remove) with the current role's permissions and the bit we want to enable (permission to give). This bit has to be also 1. For this, the following function was created, returning the resulting bit array:
[source,python]
----
def calc(bit_array: int, perm: Perm, operation: PermOperation) -> int:
if operation == PermOperation.ADD:
return bit_array | perm.value
return bit_array & ~perm.value
----