Skip to content

Repository files navigation

AIRGAP Backend

AIRGAP is a secure file management platform where users can upload, store, and retrieve encrypted files across repositories. With Role-Based Access Control (RBAC), AIRGAP ensures users can only perform actions their role allows. Every file remains encrypted both in storage and in transit, and is digitally signed to guarantee its integrity and authenticity. All actions are logged to ensure auditability and compliance.

Getting Started

  1. Clone the repository and navigate to the project directory:

    git clone https://github.com/adithya-menon-r/airgap.backend.git
    cd airgap.backend
  2. Create a virtual environment and activate it:

    python -m venv .venv
    source .venv/bin/activate 
  3. Install the dependencies:

    pip install -r requirements.txt
  4. Generate the .env file and update the environment variables:

    cp .env.example .env
  5. Generate the RSA key pair:

    mkdir -p keys
    openssl genrsa -out keys/private_key.pem 2048
    openssl rsa -in keys/private_key.pem -pubout -out keys/public_key.pem
  6. Run database migrations:

    alembic upgrade head
  7. Start the development server:

    uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

The API will be available at http://localhost:8000

Security Components

1. Authentication

AIRGAP implements a two-factor authentication flow following the NIST SP 800-63-2 E-Auth guidelines:

  • Password Authentication: Users authenticate with a password, which is validated using bcrypt with a SHA-256 pre-hash. A successful validation only allows the user to proceed to the second factor.
  • TOTP (Time-Based One-Time Password): Users verify a time-based OTP from an authenticator app (Google Authenticator / Authy) as the second factor. The JWT access token is issued only after both factors are verified successfully.

2. Authorisation & Access Control

AIRGAP implements a Role-Based Access Control (RBAC) model using an Access Control Matrix. It is enforced at the route level through the PermissionChecker class and FastAPI's Depends injection.

If a user has no role, or their role lacks the required permission, a 403 Forbidden is returned and the ACCESS_DENIED event is logged with the user's IP address.

Subjects (Roles)

Role Description
admin Full system access
senior_dev Can manage repositories and read/write files
junior_dev Can read and write files within assigned repositories
auditor Read only access to audit logs; cannot access files or repos

Objects (Resources)

Resource Description
USER_MANAGEMENT Create users, assign roles
REPOSITORY_MANAGEMENT Create, delete, assign users to repos
REPOSITORY_READ List and view repositories
FILE_WRITE Upload files
FILE_READ Access and decrypt files
AUDIT_LOGS View audit logs, run integrity scans

Access Control Matrix

Role User Management Repository Management Repository Read File Write File Read Audit Logs
admin Yes Yes Yes Yes Yes Yes
senior_dev No Yes Yes Yes Yes No
junior_dev No No Yes Yes Yes No
auditor No No No No No Yes

3. Encryption

AIRGAP uses a Digital Envelope mechanism. It uses both symmetric and asymmetric encryption (AES-GCM & RSA) to ensure that the file content is always encrypted in transit and at rest.

For the asymmetric encryption, the server uses the RSA-2048 key pair that is generated and stored in the keys/ directory. The public key is exposed to the client via the GET /auth/server-public-key endpoint.

File Upload

  1. The client first generates a random AES-256 key and encrypts the file content with it.
  2. It then fetches the server's public key and uses it to wrap the AES key.
  3. The encrypted AES key envelope is sent along with the encrypted file in the upload request.
  4. On the server, the AES key is recovered by decrypting the envelope using the server's private key.
  5. The recovered AES key is then re-encrypted using a server side master key via AES-256-GCM and then stored in the database.
  6. The encrypted file content is written to disk as received.

File Access

To access a file, the process is reversed:

  1. The server unwraps the AES key from the database using the master key.
  2. It then re-encrypts it with the client's RSA public key (received with the file access request). This ensures that only the requesting client can decrypt it.
  3. It then retrieves the encrypted file from disk and sends it along with the AES key envelope to the client.
  4. The client unwraps the AES key using its RSA private key and then uses it to decrypt the file content.

4. Hashing

Password Hashing

Passwords are saved using a double-hashing strategy:

  1. SHA-256 pre-hash: The raw password from the client is first hashed with SHA-256. This normalises the input length for bcrypt's 72-byte limit.
  2. bcrypt: brcypt generates a cryptographically random salt and uses it to hash the SHA-256 hex digest. The resulting salted hash is then stored in the database.

File Hashing

When uploading a file, the client computes a SHA-256 hash of the plaintext file and sends it in the upload payload. This hash is stored in the database and used for verification during the integrity scans.

5. Digital Signature

Each uploaded file is signed with a per-user HMAC-SHA256 signature. This binds the file to its uploader and is used to detect tampering.

Instead of using a single shared signing key, a unique signing key is derived for each user using HKDF (SHA-256), keyed off the server's SERVER_SIGNING_SECRET with the user_id as the derivation context. This ensures each user's signature is unique and cryptographically isolated.

6. Integrity Scan

The Integrity Scan is implemented to check for tampering and inconsistencies in stored data. When run, each file is decrypted, their SHA-256 hashes are re-computed & compared with the stored hash, and their HMAC signatures are validated.

Any file that is missing, has a hash mismatch, fails decryption, or has an invalid signature is flagged as tampered and logged as an INTEGRITY_FAIL.

Scripts to Demonstrate Tampering

  • tamper.py is used to simulate some kind of tampering with the file content when stored on disk:

    python tamper.py uploads/<repo_id>/<filename>

    The script unwraps the AES Key using the server's master key and uses it to decrypt the file. It then appends extra bytes to the plaintext, and re-encrypts it and saves it back to disk.

    The file on disk looks like a valid encrypted file but during the integrity scan, its hash will no longer match the hash computed during upload and it will be flagged.

  • restore.py undoes the tampering process:

    python restore.py uploads/<repo_id>/<filename>

    It decryps the file and removes the extra bytes that were appended to the plaintext and re-encrypts it. This restores the file to its original content.

License

This project is licensed under the MIT LICENSE.

About

Backend for AIRGAP, a secure file management platform with RBAC, encrypted file storage, digital signatures and an audit trail

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages