Skip to content

Commit

Permalink
feat(security): implement index encryption (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
a1ex4 committed Dec 10, 2024
1 parent d7edcbd commit 42debc5
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 6 deletions.
6 changes: 5 additions & 1 deletion app/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify, send_from_directory
from flask import Flask, render_template, request, redirect, url_for, jsonify, send_from_directory, Response
from flask_login import LoginManager
from functools import wraps
import yaml
Expand Down Expand Up @@ -172,6 +172,10 @@ def access_tinfoil_shop():
shop["referrer"] = f"https://{request.verified_host}"

shop["files"] = gen_shop_files(db)

if app_settings['shop']['encrypt']:
return Response(encrypt_shop(shop), mimetype='application/octet-stream')

return jsonify(shop)

if all(header in request.headers for header in TINFOIL_HEADERS):
Expand Down
2 changes: 1 addition & 1 deletion app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"shop": {
"motd": "Welcome to your own shop!",
"public": False,
"encrypt": False,
"encrypt": True,
"clientCertPub": "-----BEGIN PUBLIC KEY-----",
"clientCertKey": "-----BEGIN PRIVATE KEY-----",
"host": "",
Expand Down
41 changes: 41 additions & 0 deletions app/shop.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
from db import *
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
import zstandard as zstd
import random
import json

# https://github.com/blawar/tinfoil/blob/master/docs/files/public.key 1160174fa2d7589831f74d149bc403711f3991e4
TINFOIL_PUBLIC_KEY = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPdrJigQ0rZAy+jla7hS
jwen8gkF0gjtl+lZGY59KatNd9Kj2gfY7dTMM+5M2tU4Wr3nk8KWr5qKm3hzo/2C
Gbc55im3tlRl6yuFxWQ+c/I2SM5L3xp6eiLUcumMsEo0B7ELmtnHTGCCNAIzTFzV
4XcWGVbkZj83rTFxpLsa1oArTdcz5CG6qgyVe7KbPsft76DAEkV8KaWgnQiG0Dps
INFy4vISmf6L1TgAryJ8l2K4y8QbymyLeMsABdlEI3yRHAm78PSezU57XtQpHW5I
aupup8Es6bcDZQKkRsbOeR9T74tkj+k44QrjZo8xpX9tlJAKEEmwDlyAg0O5CLX3
CQIDAQAB
-----END PUBLIC KEY-----'''

def gen_shop_files(db):
shop_files = []
Expand All @@ -21,3 +39,26 @@ def gen_shop_files(db):
'size': size
})
return shop_files

def encrypt_shop(shop):
input = json.dumps(shop).encode('utf-8')
# random 128-bit AES key (16 bytes), used later for symmetric encryption (AES)
aesKey = random.randint(0,0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF).to_bytes(0x10, 'big')
# zstandard compression
flag = 0xFD
cctx = zstd.ZstdCompressor(level=22)
buf = cctx.compress(input)
sz = len(buf)

# Encrypt the AES key with RSA, PKCS1_OAEP padding scheme
pubKey = RSA.importKey(TINFOIL_PUBLIC_KEY)
cipher = PKCS1_OAEP.new(pubKey, hashAlgo = SHA256, label=b'')
# Now the AES key can only be decrypted with Tinfoil private key
sessionKey = cipher.encrypt(aesKey)

# Encrypting the Data with AES
cipher = AES.new(aesKey, AES.MODE_ECB)
buf = cipher.encrypt(buf + (b'\x00' * (0x10 - (sz % 0x10))))

binary_data = b'TINFOIL' + flag.to_bytes(1, byteorder='little') + sessionKey + sz.to_bytes(8, 'little') + buf
return binary_data
6 changes: 3 additions & 3 deletions app/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ <h2 class="pb-3">Shop</h2>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="encryptShopCheck"
aria-describedby="encryptShopCheckHelp" disabled="disabled">
aria-describedby="encryptShopCheckHelp">
<label class="form-check-label" for="encryptShopCheck">Encrypt shop</label>
<div id="encryptShopCheckHelp" class="form-text">Serve encrypted shop, so that only Tinfoil clients
can access the content (coming soon).</div>
<div id="encryptShopCheckHelp" class="form-text">Serve encrypted and compressed shop, so that only Tinfoil clients
can access the content. <strong>Strongly suggested to enable it for security</strong>.</div>
</div>

<div class="mb-3">
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ watchdog==4.0.2
Werkzeug==3.0.3

# NSTools
zstandard
zstandard==0.23.0
enlighten
pycryptodome

0 comments on commit 42debc5

Please sign in to comment.