Finished :>
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
This commit is contained in:
parent
dc7a98169d
commit
2c0061a177
|
@ -3,7 +3,6 @@
|
||||||
# sio_2425_project
|
# sio_2425_project
|
||||||
|
|
||||||
# Group members
|
# Group members
|
||||||
- A
|
- Rúben Gomes (113435)
|
||||||
- B
|
- João Bastos (113470)
|
||||||
- C
|
- Tiago Garcia (114184)
|
||||||
|
|
||||||
|
|
|
@ -1 +1,11 @@
|
||||||
|
# SIO-2425 Report
|
||||||
|
|
||||||
|
## Group
|
||||||
|
|
||||||
|
- João Pedro Fonseca Bastos - 113470 - joaop.bastos@ua.pt
|
||||||
|
- Rúben da Loura Cristóvão Gomes - 113435 - rlcg@ua.pt
|
||||||
|
- Tiago Rocha Garcia - 114184 - tiago.rgarcia@ua.pt
|
||||||
|
|
||||||
|
## Report
|
||||||
|
|
||||||
|
This report was written in [AsciiDoc](https://asciidoctor.org/) and compiled using the `asciidoctor` tool.
|
|
@ -280,7 +280,7 @@ JWT also supports signatures, so with a given secret key, the server can verify
|
||||||
====== Tampering
|
====== Tampering
|
||||||
With the support of signatures, the server can verify the integrity of the token, and if it was tampered with, the signature would not match the content of the token.
|
With the support of signatures, the server can verify the integrity of the token, and if it was tampered with, the signature would not match the content of the token.
|
||||||
|
|
||||||
Another added layer of security could be the use of a counter, that is incremented with each request, where the server verifies if the counter is correct, and vice-versa.
|
Another added layer of security could be the use of a counter, that is incremented with each request, where the server verifies if the counter is correct, and vice versa.
|
||||||
|
|
||||||
====== Null Cipher
|
====== Null Cipher
|
||||||
The cipher python package used in the project, `cryptohazmat`, uses AES-CFB, that avoids null ciphers. Of course, any failure within the package (or any other package) due to an update or a bug could eventually lead to a null cipher attack.
|
The cipher python package used in the project, `cryptohazmat`, uses AES-CFB, that avoids null ciphers. Of course, any failure within the package (or any other package) due to an update or a bug could eventually lead to a null cipher attack.
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
== Conclusions
|
||||||
|
|
||||||
|
The SIO-2425 project successfully demonstrates the practical application of critical security principles, including authentication, access control, session management, and cryptography. Through the implementation of modularized server architecture, robust session handling, and encrypted communication mechanisms, the project adheres to some industry standards, where analyzing the OWASP ASVS gives the developers a broader landscape of what are the best practices, and what needs to be done in order to achieve a more secure application, even though of course it'll never be fully secure.
|
||||||
|
|
||||||
|
Despite these achievements, the analysis highlighted areas requiring further improvement, such as enhanced mechanisms for session re-authentication, secure session management features, and the ability to terminate active sessions after sensitive changes. Addressing these issues would further improve the system's security posture and resilience against potential vulnerabilities.
|
||||||
|
|
||||||
|
The methodologies and decisions applied throughout this project underline the importance of secure design in software development. By integrating tools like Diffie-Hellman key exchange, AES encryption, and SHA256 hashing, the project ensures data confidentiality, integrity, and authenticity. It was also a great learning opportunity for the authors, when it comes to server-side development and design, as well as the importance of secure coding practices.
|
||||||
|
|
||||||
|
Future work could focus on refining the system to meet additional ASVS requirements and expanding its usability in real-world applications. Overall, this project stands as a testament to the successful implementation of secure application principles and the importance of continuous learning and iteration in cybersecurity practices.
|
|
@ -1,46 +1,61 @@
|
||||||
== Decisions
|
== Decisions
|
||||||
In this topic, it'll be presnted 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.
|
|
||||||
|
|
||||||
|
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
|
=== Usage of the Diffie-Hellman Key Exchange
|
||||||
The Diffie-Hellman key exchange is used in this project to securely create and mantain 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 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`).
|
The key generation (public and private) is done using the parameters agreed on both ends (using the `dh` package from `cryptography`).
|
||||||
|
|
||||||
|
|
||||||
=== Symmetric Encryption
|
=== 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.
|
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 a Initialization Vector(IV) of 16 bytes, with it being randomly generated.
|
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
|
=== 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 stem:[2^11] bytes.
|
|
||||||
|
|
||||||
|
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
|
=== 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 API, please run `rm -r ~/.sio/`
|
|
||||||
|
|
||||||
|
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
|
=== 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.
|
|
||||||
|
|
||||||
|
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
|
=== Database
|
||||||
The authors of this project have chosen to use a database to store all server-side 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. When needed, it can be reset using a endpoint mentioned in the Features chapter.
|
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
|
=== Modularized Server
|
||||||
The server is modularized in order to make it easier to maintain and expand. 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.
|
|
||||||
|
|
||||||
|
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
|
=== 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:
|
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]
|
[source,python]
|
||||||
----
|
----
|
||||||
|
class Perm(Enum):
|
||||||
DOC_ACL = 0b000000000001
|
DOC_ACL = 0b000000000001
|
||||||
DOC_READ = 0b000000000010
|
DOC_READ = 0b000000000010
|
||||||
DOC_DELETE = 0b000000000100
|
DOC_DELETE = 0b000000000100
|
||||||
|
@ -50,8 +65,23 @@ 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.
|
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
|
==== 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)
|
|
||||||
|
|
||||||
==== Adding 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:
|
||||||
To add a permission to a role, all that is needed is a OR operation with the current role's permissions and the bit we want to enable (permission to give). This bit has to be also 1.
|
|
||||||
|
|
||||||
|
[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
|
||||||
|
----
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
[[features]]
|
||||||
== Features
|
== Features
|
||||||
|
|
||||||
The features of the project are the ones present in the course project description, but with an extra feature, the possibility to reset the database of the server. This was shown to be useful for testing purposes, but it should be disabled/deleted in a production environment.
|
The features of the project are the ones present in the course project description, but with an extra feature, the possibility to reset the database of the server. This was shown to be useful for testing purposes, but it should be disabled/deleted in a production environment.
|
||||||
|
@ -221,9 +222,11 @@ a| * `Authorization: token`
|
||||||
|
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
<<<
|
||||||
|
|
||||||
=== Client Interaction
|
=== Client Interaction
|
||||||
|
|
||||||
For the client, each command is executed via terminal and it is used multiple tools with specific functionalities:
|
For the client, each command is executed via terminal, and it is used multiple tools with specific functionalities:
|
||||||
|
|
||||||
* `argparse` footnote:[https://docs.python.org/3/library/argparse.html] → Check for errors in arguments given by the user.
|
* `argparse` footnote:[https://docs.python.org/3/library/argparse.html] → Check for errors in arguments given by the user.
|
||||||
* `logging` footnote:[https://docs.python.org/3/library/logging.html] → Logging system to send out messages such as errors.
|
* `logging` footnote:[https://docs.python.org/3/library/logging.html] → Logging system to send out messages such as errors.
|
||||||
|
@ -231,7 +234,7 @@ For the client, each command is executed via terminal and it is used multiple to
|
||||||
* `requests` footnote:[https://requests.readthedocs.io/en/latest/] → Main library to allow communication from the client to the API.
|
* `requests` footnote:[https://requests.readthedocs.io/en/latest/] → Main library to allow communication from the client to the API.
|
||||||
* `JSON` footnote:[https://docs.python.org/3/library/json.html] → Main library to store and exchange data between the client and API.
|
* `JSON` footnote:[https://docs.python.org/3/library/json.html] → Main library to store and exchange data between the client and API.
|
||||||
|
|
||||||
For every command the argument `-r` is present to set the API's address. It is needed to define if it wasn't previously, otherwise an error is cast with the corresponding message.
|
For every command the argument `-r` is present to set the APIs address. It is needed to define if it wasn't previously, otherwise an error is cast with the corresponding message.
|
||||||
|
|
||||||
|
|
||||||
==== Generating the Subject's Credentials
|
==== Generating the Subject's Credentials
|
||||||
|
@ -244,7 +247,7 @@ The command `rep_create_org` creates an organization. In order to do that, the c
|
||||||
|
|
||||||
|
|
||||||
==== Creating a session
|
==== Creating a session
|
||||||
For the client to use the Authenticated API, the command `rep_create_session` allows the user to create a session and assume an identity. This command also protects information that shouldn't be visible to outsiders when it's being transfered between the client and the server.
|
For the client to use the Authenticated API, the command `rep_create_session` allows the user to create a session and assume an identity. This command also protects information that shouldn't be visible to outsiders when it's being transferred between the client and the server.
|
||||||
|
|
||||||
To protect the information, the client and the server initiate a Diffie-Hellman footnote:[https://cryptography.io/en/latest/hazmat/primitives/asymmetric/dh/] key exchange where both create a key pair with the same parameters and share each other their public key to derive with their own private key and obtain a common key which can be used to encrypt and decrypt information between both entities.
|
To protect the information, the client and the server initiate a Diffie-Hellman footnote:[https://cryptography.io/en/latest/hazmat/primitives/asymmetric/dh/] key exchange where both create a key pair with the same parameters and share each other their public key to derive with their own private key and obtain a common key which can be used to encrypt and decrypt information between both entities.
|
||||||
|
|
||||||
|
@ -266,13 +269,12 @@ server_public_key = serialization.load_pem_public_key(bytes.fromhex(response['pu
|
||||||
derived_key = derive_keys(private_key, server_public_key)
|
derived_key = derive_keys(private_key, server_public_key)
|
||||||
----
|
----
|
||||||
|
|
||||||
If the exchange is succesful, the client will attempt to login using it's private key that should be given when executing this command.
|
If the exchange is successful, the client will attempt to log in using its private key that should be given when executing this command. This process is explained in the decision chapter, under link:#decisions_authentication[Authentication], but in short, the server will send a challenge to the client, which the client will sign with its private key (from a different key pair from Diffie-Hellman) and send back to the server. If the server can verify the signature, the client is authenticated and a session is created. This is the same method used in SSH.
|
||||||
|
|
||||||
|
|
||||||
==== Listing Organizations
|
==== Listing Organizations
|
||||||
The command `rep_list_org` lists all organizations present in the server. Since it requires no authentication, it is a simple command that sends a GET request to the API and prints the response.
|
The command `rep_list_org` lists all organizations present in the server. Since it requires no authentication, it is a simple command that sends a GET request to the API and prints the response.
|
||||||
|
|
||||||
However, it is important to note that the response is encrypted and must be decrypted before being printed. In order to achieve this, the client uses a symmetric encryption algorithm that uses a Initialization Vector (IV) to decrypt the response. This is done by the function `decrypt_request_with_iv` that receives the encrypted response, where it separates the IV from the encrypted text (first 16 bytes being the IV) and returns the decrypted response.
|
However, it is important to note that the response is encrypted and must be decrypted before being printed. In order to achieve this, the client uses a symmetric encryption algorithm that uses an Initialization Vector (IV) to decrypt the response. This is done by the function `decrypt_request_with_iv` that receives the encrypted response, where it separates the IV from the encrypted text (first 16 bytes being the IV) and returns the decrypted response.
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
|
@ -303,6 +305,7 @@ With the command `rep_assume_role`, the user can assume a role in the session. T
|
||||||
|
|
||||||
If everything is correct, the server will return a 200 status code, otherwise it will return an error message. The API will print the message to the screen and exit with the corresponding status code.
|
If everything is correct, the server will return a 200 status code, otherwise it will return an error message. The API will print the message to the screen and exit with the corresponding status code.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
|
||||||
==== Adding a role to the organization
|
==== Adding a role to the organization
|
||||||
The command `rep_add_role` allows the user to add a role to the organization. This command requires the user to be authenticated and the role to be added. The role is sent to the server in a `POST` request, where the role name is sent in the body of the request. The data is encrypted with the derived key from the Diffie-Hellman key exchange.
|
The command `rep_add_role` allows the user to add a role to the organization. This command requires the user to be authenticated and the role to be added. The role is sent to the server in a `POST` request, where the role name is sent in the body of the request. The data is encrypted with the derived key from the Diffie-Hellman key exchange.
|
||||||
|
@ -311,7 +314,7 @@ If the request is successful, the server will return a 201 status code, otherwis
|
||||||
|
|
||||||
|
|
||||||
==== Adding permissions/user to a role
|
==== Adding permissions/user to a role
|
||||||
Given a role name and a valid permission/username, the `rep_add_permission` command allows a user to add certain permissions to a specific role in a organization (if the user has permissions to do that) or a username to that role.
|
Given a role name and a valid permission/username, the `rep_add_permission` command allows a user to add certain permissions to a specific role in an organization (if the user has permissions to do that) or a username to that role.
|
||||||
|
|
||||||
First, since there's only some permissions, it's checked if it corresponds to one of them and if not, it assumes it's a username.
|
First, since there's only some permissions, it's checked if it corresponds to one of them and if not, it assumes it's a username.
|
||||||
|
|
||||||
|
@ -321,7 +324,7 @@ Like the other commands, if the request is successful, the server will return a
|
||||||
|
|
||||||
|
|
||||||
==== Removing a permission/user from a role
|
==== Removing a permission/user from a role
|
||||||
Similar to the previous command, the `rep_remove_permission` command allows a user to remove certain permissions from a specific role in a organization (if the user has permissions to do that) or a username from that role.
|
Similar to the previous command, the `rep_remove_permission` command allows a user to remove certain permissions from a specific role in an organization (if the user has permissions to do that) or a username from that role.
|
||||||
|
|
||||||
It follows the same steps as the `rep_add_permission` command, but instead of adding, it removes the permission/username from the role.
|
It follows the same steps as the `rep_add_permission` command, but instead of adding, it removes the permission/username from the role.
|
||||||
|
|
||||||
|
@ -355,7 +358,7 @@ Like before, the roles are printed to the screen, and any errors would also be p
|
||||||
|
|
||||||
|
|
||||||
==== Listing subjects with a role
|
==== Listing subjects with a role
|
||||||
The following command `rep_list_role_subjects` is similar to the previous command (`rep_list_roles`), except this command will return the subjects that have a specific role. This role is given as a argument and should be provided beforehand when executing the command.
|
The following command `rep_list_role_subjects` is similar to the previous command (`rep_list_roles`), except this command will return the subjects that have a specific role. This role is given as an argument and should be provided beforehand when executing the command.
|
||||||
|
|
||||||
|
|
||||||
==== Listing roles of a subject
|
==== Listing roles of a subject
|
||||||
|
@ -367,19 +370,19 @@ Another command with a similar implementation of the previous ones, the `rep_lis
|
||||||
|
|
||||||
|
|
||||||
==== Listing roles with a permission
|
==== Listing roles with a permission
|
||||||
Once again, this command has a almost identical implementation of the previous commands, the command `rep_list_permission_roles` gives the user a list of roles that have a specific permission, given as a argument before calling said command.
|
Once again, this command has an almost identical implementation of the previous commands, the command `rep_list_permission_roles` gives the user a list of roles that have a specific permission, given as an argument before calling said command.
|
||||||
|
|
||||||
|
|
||||||
==== Adding a subject to a organization
|
==== Adding a subject to an organization
|
||||||
The command `rep_add_subject` aims to give the possibility of a user to be able to add another user to the current organization. This is, of course, a command that requires specific permissions in order to do this.
|
The command `rep_add_subject` aims to give the possibility of a user to be able to add another user to the current organization. This is, of course, a command that requires specific permissions in order to do this.
|
||||||
|
|
||||||
First, it checks for the existente of a session file. Then, it sends a `POST` request to the server, with the informatio of the subject to be added. These include the `username`, `full_name`, `email` and `public_key`. This content is encrypted with the derived key from the Diffie-Hellman key exchange from the user that is executing the command.
|
First, it checks for the existence of a session file. Then, it sends a `POST` request to the server, with the information of the subject to be added. These include the `username`, `full_name`, `email` and `public_key`. This content is encrypted with the derived key from the Diffie-Hellman key exchange from the user that is executing the command.
|
||||||
|
|
||||||
According to the success of the previous request, a message will be printed back to the user.
|
According to the success of the previous request, a message will be printed back to the user.
|
||||||
|
|
||||||
|
|
||||||
==== Suspending a subject
|
==== Suspending a subject
|
||||||
This command (`rep_suspend_subject`) allows for a user (authenticated and with the required permission) to suspend a subject from a organization.
|
This command (`rep_suspend_subject`) allows for a user (authenticated and with the required permission) to suspend a subject from an organization.
|
||||||
|
|
||||||
The username is parsed in the URL, and the session token is, as usual, sent in the header of the request.
|
The username is parsed in the URL, and the session token is, as usual, sent in the header of the request.
|
||||||
|
|
||||||
|
@ -415,7 +418,7 @@ req = requests.post(f'http://{state['REP_ADDRESS']}/file/upload/metadata',
|
||||||
headers=headers)
|
headers=headers)
|
||||||
----
|
----
|
||||||
|
|
||||||
If the upload is successful, the client proceeds to upload the encrypted content, along with an hash of the content for the server to check for integrity.
|
If the upload is successful, the client proceeds to upload the encrypted content, along with a hash of the content for the server to check for integrity.
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
|
@ -435,14 +438,16 @@ In order to modify the ACL of an organization, the user must have the permission
|
||||||
* `DOC_READ` → Allows the person holding the given role to read the document.
|
* `DOC_READ` → Allows the person holding the given role to read the document.
|
||||||
* `DOC_DELETE` → Allows the person holding the given role to delete the *file_handle*.
|
* `DOC_DELETE` → Allows the person holding the given role to delete the *file_handle*.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
|
||||||
==== Getting a document's metadata
|
==== Getting a document's metadata
|
||||||
Every document has it's metadata that includes the `file handle` and `key`. To get the metadata of a specific document, the command `rep_get_doc_metadata` sends a `GET` request and with the derived key the response is decrypted. Using the `file handle` we can then get the file.
|
Every document has it's metadata that includes the `file handle` and `key`. To get the metadata of a specific document, the command `rep_get_doc_metadata` sends a `GET` request and with the derived key the response is decrypted. Using the `file handle` we can then get the file.
|
||||||
|
|
||||||
==== Getting a file's content
|
==== Getting a file's content
|
||||||
This command (`rep_get_file`) is relatively simple, the client provides the file handle to the server and it is given the file's content which is either written on the screen or saved in a file given by the user.
|
This command (`rep_get_file`) is relatively simple, the client provides the file handle to the server, and it is given the file's content which is either written on the screen or saved in a file given by the user.
|
||||||
|
|
||||||
==== Decrypting a file
|
==== Decrypting a file
|
||||||
Given the document's metadata and the file's content, what's left to do is to get the actual content by decrypting it. As such, using the command `rep_decrypt_file` the file's content is decrypted using the key given in it's metadata
|
Given the document's metadata and the file's content, what's left to do is to get the actual content by decrypting it. As such, using the command `rep_decrypt_file` the file's content is decrypted using the key given in its metadata
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
|
@ -458,7 +463,7 @@ doc_name = digest.get_hash(bytes(args.name, encoding='utf-8'))
|
||||||
metadata = requests.get(f'http://{state['REP_ADDRESS']}/file/get/' + doc_name + '/metadata', headers={'Authorization': args.session['token']})
|
metadata = requests.get(f'http://{state['REP_ADDRESS']}/file/get/' + doc_name + '/metadata', headers={'Authorization': args.session['token']})
|
||||||
----
|
----
|
||||||
|
|
||||||
The metadata is then decrypted and we get the `file handle` needed to get it's content by sending another `GET` request. If successful, the hash of the file's content must be equal to the file handle, this way we see if the file's integrity is maintained.
|
The metadata is then decrypted, and we get the `file handle` needed to get it's content by sending another `GET` request. If successful, the hash of the file's content must be equal to the file handle, this way we see if the file's integrity is maintained.
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
|
@ -469,7 +474,7 @@ if not digest.get_hash(file) == metadata['file_handle']:
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
----
|
----
|
||||||
|
|
||||||
Once having both the metadata and the file's content, the client decrypts it like it's being done in the command `rep_decrypt_file`. The file's content is written to a temporary file and it's used symmetric decryption to get the plaintext using the key stored in the metadata.
|
Once having both the metadata and the file's content, the client decrypts it like it's being done in the command `rep_decrypt_file`. The file's content is written to a temporary file, and it's used symmetric decryption to get the plaintext using the key stored in the metadata.
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
|
@ -481,17 +486,26 @@ os.remove(BASE_DIR + 'encrypted_file')
|
||||||
----
|
----
|
||||||
|
|
||||||
==== Listing documents
|
==== Listing documents
|
||||||
The command `rep_list_docs` allows the user to get a list of all documents in the organization. To make it organized, the command can be executed with a date and specify if the documents must be older, newer or created in that specific date or it can be filtered by who created the document.
|
The command `rep_list_docs` allows the user to get a list of all documents in the organization.
|
||||||
|
|
||||||
|
To make it organized, the command can be executed with a date and specify if the documents must be older, newer or created in that specific date, or it can be filtered by who created the document.
|
||||||
|
|
||||||
The payload simply contains nothing if there's no subject or date given, or it contains the username, date or both.
|
The payload simply contains nothing if there's no subject or date given, or it contains the username, date or both.
|
||||||
|
|
||||||
|
The following example shows how the endpoint may be called specifying the date and the username.
|
||||||
|
|
||||||
[source, python]
|
[source, python]
|
||||||
----
|
----
|
||||||
# Document created after 20/12/2024
|
payload = {} # Payload may be sent empty if no filters are needed
|
||||||
payload['datetime'] = {'value' : 20/12/2024, 'relation' : 'nt'}
|
|
||||||
|
# If the username is given
|
||||||
|
payload['username'] = args.username[0]
|
||||||
|
# If the date is given
|
||||||
|
payload['datetime'] = {'value': args.date[0], 'relation': args.date[1]}
|
||||||
|
|
||||||
payload = json.dumps(payload)
|
payload = json.dumps(payload)
|
||||||
payload = encrypt(payload, derived_key).hex()
|
payload = encrypt(payload, derived_key).hex()
|
||||||
|
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'Authorization': args.session['token'],
|
'Authorization': args.session['token'],
|
||||||
'Content-Type': 'application/octet-stream'
|
'Content-Type': 'application/octet-stream'
|
||||||
|
|
|
@ -10,6 +10,7 @@ Rúben Gomes (113435); João Bastos (113470); Tiago Garcia (114184)
|
||||||
:stylesheet: style.css
|
:stylesheet: style.css
|
||||||
:sectnums:
|
:sectnums:
|
||||||
:sectlinks:
|
:sectlinks:
|
||||||
|
:stem: latexmath
|
||||||
:!last-update-label:
|
:!last-update-label:
|
||||||
|
|
||||||
== Introduction
|
== Introduction
|
||||||
|
@ -32,4 +33,4 @@ include::analysis.adoc[]
|
||||||
|
|
||||||
<<<
|
<<<
|
||||||
|
|
||||||
include::results_conclusions.adoc[]
|
include::conclusions.adoc[]
|
||||||
|
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
||||||
== Results and Conclusions
|
|
||||||
|
|
||||||
This section will present the outcomes of the project, including any data collected, analyses performed, and key findings.
|
|
|
@ -5,10 +5,9 @@
|
||||||
a::after {
|
a::after {
|
||||||
content: none !important; /* Prevent showing URLs in print */
|
content: none !important; /* Prevent showing URLs in print */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
font-family: 'Open Sans', sans-serif !important;
|
page-break-after: avoid !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, pre {
|
p, pre {
|
||||||
|
@ -16,6 +15,11 @@ p, pre {
|
||||||
page-break-inside: avoid !important;
|
page-break-inside: avoid !important;
|
||||||
page-break-after: avoid !important;
|
page-break-after: avoid !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-family: 'Open Sans', sans-serif !important;
|
||||||
|
}
|
||||||
|
|
||||||
p:not(.tableblock) {
|
p:not(.tableblock) {
|
||||||
text-align: justify !important;
|
text-align: justify !important;
|
||||||
|
|
Loading…
Reference in New Issue