This project is a solution to the Backend Coding Challenge from Swizil Ltd. It is designed to test backend skills, including API design, encryption, debugging, and secure data handling.
The task was to build a secure messaging backend with the following features:
- Store encrypted messages for users using AES encryption.
- Allow only the original user to decrypt and retrieve their messages.
- Debug and fix a broken decryption function.
The challenge is designed to be completed within 60-90 minutes. However, additional time can be spent refining and improving the solution.
- Store encrypted messages per user using AES encryption.
- Decrypt messages only for the original user who encrypted them.
- Fix the broken decryption logic.
-
POST /messages
- Stores an encrypted message for a user.
- Encrypts the message using AES-256 encryption before storage.
-
GET /messages/:userId
- Retrieves all messages for the specified user.
- Decrypts messages before returning them to the user.
-
POST /debug/decrypt
- Fixes the broken decryption function provided in the task.
- Provides an explanation of the fix.
- Encryption method: AES (AES-256) encryption.
- Encryption library:
crypto
(Node.js). - IV (Initialization Vector): A random IV is generated per message and embedded in the encrypted payload for decryption.
The encrypted values are stored in base64 format.
-
Encryption Method: I chose AES-256-CBC because it is widely considered secure and is commonly used for encrypting sensitive data. The CBC (Cipher Block Chaining) mode ensures that the encryption is not deterministic and requires an IV for each message.
-
Ensuring Original User Access: Each user’s message is encrypted with a key derived from the user’s userId. Only the user with the correct
userId
will be able to decrypt the message. -
IV Storage: The IV is stored within the encrypted message so it can be extracted and used during the decryption process. The IV is random for each message to ensure that identical messages encrypted multiple times do not produce the same ciphertext.
-
Preventing User ID Spoofing: By using a user-specific key derived from the user’s
userId
, the system ensures that only users with the correctuserId
can decrypt their messages. Additionally, any unauthorized access attempts will result in decryption failures.
A broken decryption function was provided in the challenge. I have identified and fixed the issues in the function and written test cases to validate the fix.
- Encryption/Decryption Logic: The encryption and decryption logic is fully functional, and only the user who encrypted the message can decrypt it.
- Code Structure: The code is clean, modular, and follows best practices.
- Security: Secure handling of messages and per-user access is ensured through AES encryption and proper IV management.
- Design Explanation: A thoughtful explanation of the design decisions is provided in the comments and the README.
- Message Expiry: I implemented a feature to automatically delete messages after 10 minutes of creation.
- Authentication: Basic token-based authentication was added.
- Unit Tests: Unit tests were written for encryption, storage, and retrieval.
To run this project locally, follow these steps:
- Node.js (>=12.0.0)
- npm (>=6.0.0)
-
Clone the repository:
git clone https://github.com/costa253-hash/secure-messaging.git
-
Navigate into the project folder:
cd secure-messaging
-
Install the dependencies:
npm install
-
Run the application:
npm start
-
The API will be running on
http://localhost:3000
.
- Encryption Method: I used AES-256-CBC for encryption, as it is widely regarded as secure. I used the
crypto
module in Node.js for encryption and decryption. - User Access: Each user’s messages are encrypted using a key derived from their
userId
. This ensures only the user with the correct ID can decrypt their messages. - IV Handling: A random IV is generated for each message and stored along with the message to be used during decryption.
- User ID Spoofing Prevention: The key for AES encryption is based on the user's
userId
, which ensures that only the authorized user can decrypt their own messages.
- The
userId
is unique for each user. - The system handles only one user at a time, and it is assumed that the user will provide valid
userId
values for storing and retrieving messages.
MIT License