initial commit

master
nihonium 2 years ago
commit 3b3c9a9417
No known key found for this signature in database
GPG Key ID: 0251623741027CFC

@ -0,0 +1 @@
Subproject commit 179b297abcc7f545163d363d366e6af723c35856

@ -0,0 +1,9 @@
FROM python:3.6-alpine
WORKDIR /dist
RUN apk add --update build-base libffi-dev openssl-dev
COPY src/requirements.txt /dist/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt && mkdir db
COPY src .
CMD ["python", "-u", "app.py"]
EXPOSE 8777

@ -0,0 +1,113 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import jwt
import socket
import socketserver
from cipher import *
from utils import *
class SignatureFailure(Exception):
pass
"""
Service connection handler
"""
class ForkingTCPServer(socketserver.ForkingTCPServer):
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
socketserver.TCPServer.server_bind(self)
class ServiceServerHandler(socketserver.BaseRequestHandler):
def __init__(self, request, client_address, server):
socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
def handle(self):
logger.info('[%s] Accepted connection', self.client_address[0])
try:
# handle commands
while True:
cmd = read_message(self.request)
logger.info('[%s] Accepted command: %s', self.client_address[0], cmd)
if cmd == b'PUSH':
logger.info('[%s] PUSH: Executing', self.client_address[0])
capsule = read_message(self.request)
game_round = read_message(self.request)
iv = read_message(self.request)
encrypted_capsule, id = encrypt(capsule, iv)
send_message(self.request, encrypted_capsule)
send_message(self.request, id)
signature = read_message(self.request)
with open('ec_public.pem', 'rb') as jwtkey:
key = jwtkey.read()
if jwt.decode(signature, key, algorithms='ES256')['message'] != 'It\'s me, Mario!':
send_message(self.request, b'-')
raise SignatureFailure
else:
save_data('db/storage.db', str(game_round), encrypted_capsule, id)
send_message(self.request, b'+')
elif cmd == b'PULL':
logger.info('[%s] PULL: Executing', self.client_address[0])
# !!!
game_round = read_message(self.request)
try:
encrypted_capsule, retrieved_id = retrieve_data('db/storage.db', str(game_round))
send_message(self.request, encrypted_capsule)
# !!!
if read_message(self.request) == b'+':
iv = read_message(self.request)
id = read_message(self.request)
if id == retrieved_id:
decrypted_capsule = decrypt(encrypted_capsule, iv)
send_message(self.request, decrypted_capsule)
else:
send_message(self.request, b'-')
except Exception as ex:
send_message(self.request, b'-')
logger.error('[%s] PULL: Exception: %s', self.client_address[0], ex)
elif cmd == b'EXIT':
send_message(self.request, b'+')
break
else:
raise Exception('[%s] Failed to process command: command %s is unknown', self.client_address[0], cmd)
except Exception as ex:
logger.error(str(ex), exc_info=True)
finally:
logger.info('[%s] Processed connection', self.client_address[0])
"""
main
"""
if __name__ == '__main__':
# initialize logging
logging.basicConfig(format='%(asctime)s [%(levelname)-5.5s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.DEBUG)
logger = logging.getLogger('service')
# initialize and spawn the server
create_database('db/storage.db')
server = ForkingTCPServer(('0.0.0.0', 8777), ServiceServerHandler)
server.serve_forever()

@ -0,0 +1,118 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher, algorithms, modes
)
KEY = b'\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08'
# region Utils
def gmul(x: int, y: int):
r = int('0b11100001' + '0' * 120, 2)
z = 0
v = x
y_bit = bin(y)[2:]
for i in range(128):
if y_bit[i] == '1':
z ^= v
if (v & 1) == 0:
v >>= 1
else:
v = (v >> 1) ^ r
return z
# endregion Utils
# region The Cipher
def encrypt_block(block):
encryptor = Cipher(
algorithms.AES(KEY),
modes.ECB(),
backend=default_backend()
).encryptor()
ciphertext = encryptor.update(block) + encryptor.finalize()
return ciphertext
def encrypt(plaintext: bytes, iv: bytes):
ciphertext = []
salt = encrypt_block(b'\x00' * 16)
blocks = []
for i in range(0, len(plaintext), 16):
blocks.append(plaintext[i:i+16])
j = [iv[:12] + b'\x00' * 3 + b'\x01', iv[:12] + b'\x00' * 3 + b'\x02']
j_int = int.from_bytes(j[1], 'big')
cnt = 0
while cnt < len(blocks):
j_bytes = j_int.to_bytes(16, 'big')
enc_j = int.from_bytes(encrypt_block(j_bytes), 'big')
enc_j_bytes = enc_j.to_bytes(16, 'big')[:len(blocks[cnt])]
enc_j = int.from_bytes(enc_j_bytes, 'big')
block_i = int.from_bytes(blocks[cnt], 'big')
ctext_i = enc_j ^ block_i
ciphertext.append(ctext_i.to_bytes(len(blocks[cnt]), 'big'))
j_int = (j_int + 1) % (2**128)
cnt += 1
id = 0
for ctext_i in ciphertext:
if len(ctext_i) != 16:
ctext_j = ctext_i + b'\x00' * (16 - len(ctext_i) % 16)
else:
ctext_j = ctext_i
id = gmul((id ^ int.from_bytes(ctext_j, 'big')), int.from_bytes(salt, 'big'))
l = len(plaintext) * 8
id = gmul(id ^ l, int.from_bytes(salt, 'big'))
id = id ^ int.from_bytes(encrypt_block(j[0]), 'big')
id = id.to_bytes(16, 'big')
print(encrypt_block(j[0]))
return b''.join(ciphertext), id
def decrypt(ciphertext: bytes, iv: bytes):
plaintext = []
blocks = []
for i in range(0, len(ciphertext), 16):
blocks.append(ciphertext[i:i+16])
j = [iv[:12] + b'\x00' * 3 + b'\x01', iv[:12] + b'\x00' * 3 + b'\x02']
j_int = int.from_bytes(j[1], 'big')
cnt = 0
while cnt < len(blocks):
j_bytes = j_int.to_bytes(16, 'big')
enc_j = int.from_bytes(encrypt_block(j_bytes), 'big')
enc_j_bytes = enc_j.to_bytes(16, 'big')[:len(blocks[cnt])]
enc_j = int.from_bytes(enc_j_bytes, 'big')
block_i = int.from_bytes(blocks[cnt], 'big')
ptext_i = enc_j ^ block_i
byte_length = ptext_i.bit_length() // 8
if ptext_i.bit_length() % 8 != 0:
byte_length += 1
plaintext.append(ptext_i.to_bytes(byte_length, 'big'))
j_int = (j_int + 1) % (2**128)
cnt += 1
return b''.join(plaintext)
# endregion The Cipher

@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGySmc8D9mKY0VGif5el/bnbIlQeR
hLEWYtvvINH/IM5W2BfgtrrZVl5dyGy7tAWqpcqluIipcmcYcHqJndIneg==
-----END PUBLIC KEY-----

@ -0,0 +1,2 @@
PyJWT
cryptography==3.3.2

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
import logging
import struct
import sqlite3
logger = logging.getLogger('service')
"""
Communication
"""
class InputOverflowException(Exception):
pass
class InputUnderflowException(Exception):
pass
def read_message(s, max_input_length=1024*16) -> bytes:
received_buffer = s.recv(8)
logger.info('[%s] Accepted connection', self.client_address[0])
if len(received_buffer) < 8:
raise InputUnderflowException('Failed to receive data: the received length is less than 8 bytes long')
to_receive = struct.unpack('<Q', received_buffer[0:8])[0]
if to_receive > max_input_length:
raise InputOverflowException('Failed to receive data: requested to accept too much data')
received_buffer = b''
while len(received_buffer) < to_receive:
data = s.recv(to_receive - len(received_buffer))
if len(data) == 0:
raise InputUnderflowException('Failed to receive data: the pipe must have been broken')
received_buffer += data
if len(received_buffer) > max_input_length:
raise InputOverflowException('Failed to receive data: accepted too much data')
return received_buffer
def send_message(s, message: bytes):
send_buffer = struct.pack('<Q', len(message)) + message
s.sendall(send_buffer)
"""
Database
"""
def create_database(db_file_path: str):
conn = sqlite3.connect(db_file_path)
with conn:
try:
cursor = conn.cursor()
cursor.execute('CREATE TABLE data (gr TEXT UNIQUE, c TEXT, id TEXT)')
except sqlite3.OperationalError as ex:
logger.error('Failed to create table: %s', ex)
conn.close()
def save_data(db_file_path: str, gr: str, c: bytes, id: bytes):
conn = sqlite3.connect(db_file_path)
try:
cursor = conn.cursor()
cursor.execute('INSERT INTO data VALUES (?,?,?)', (gr, c, id))
conn.commit()
finally:
conn.close()
def retrieve_data(db_file_path: str, gr: str) -> tuple:
conn = sqlite3.connect(db_file_path)
try:
cursor = conn.cursor()
cursor.execute('SELECT * FROM data WHERE gr=?', (gr, ))
row = cursor.fetchone()
_, c, id = row
return c, id
finally:
conn.close()

@ -0,0 +1,8 @@
version: "3.9"
services:
aesthetic:
container_name: "aesthetic_service"
build: ./build/
ports:
- "8777:8777"
restart: always

@ -0,0 +1,4 @@
FROM openjdk:11-jdk-oracle
COPY backend-1.0.0-FINAL.jar /app/editor.jar
WORKDIR /app
ENTRYPOINT ["java","-Dspring.profiles.active=prod","-jar","/app/editor.jar"]

@ -0,0 +1,35 @@
# JPA setup
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:editor}
spring.datasource.username=${MYSQL_USER:editor}
spring.datasource.password=${MYSQL_PASSWORD:password}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
# Spring misc setup
logging.level.org.springframework.web=DEBUG
# General App properties
server.port=${SERVER_PORT:8080}
app.debug=false
# App's defaults
app.defaults.admin.username=admin
app.defaults.admin.password=@dM1ni$theb3sT
# Security
app.security.password.length.min=8
app.security.password.length.max=42
app.security.auth_token.name=AuthToken
app.security.auth_token.secret=VolgaCTF2022
app.security.auth_token.validity.period=360
app.security.user.expiration.period=360
app.security.user.expiration.schedule=* 15 * * * *
# Static contents settings
app.storage.image.fs.root=/app/.data
app.storage.image.types=jpeg,png
app.storage.image.count.limit=10

@ -0,0 +1,34 @@
# JPA setup
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
# Spring misc setup
logging.level.org.springframework.web=DEBUG
# General App properties
server.port=${SERVER_PORT:8080}
app.debug=true
# App's defaults
app.defaults.admin.username=admin
app.defaults.admin.password=@dM1ni$theb3sT
# Security
app.security.password.length.min=8
app.security.password.length.max=42
app.security.auth_token.name=AuthToken
app.security.auth_token.secret=VolgaCTF2022
app.security.auth_token.validity.period=360
app.security.user.expiration.period=360
app.security.user.expiration.schedule=* 15 * * * *
# Static contents settings
app.storage.image.fs.root=./target/static
app.storage.image.types=jpeg,png
app.storage.image.count.limit=10

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

@ -0,0 +1,73 @@
- "BOOT-INF/lib/spring-boot-2.6.1.jar"
- "BOOT-INF/lib/spring-context-5.3.13.jar"
- "BOOT-INF/lib/spring-boot-autoconfigure-2.6.1.jar"
- "BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar"
- "BOOT-INF/lib/spring-core-5.3.13.jar"
- "BOOT-INF/lib/spring-jcl-5.3.13.jar"
- "BOOT-INF/lib/snakeyaml-1.29.jar"
- "BOOT-INF/lib/jackson-datatype-jdk8-2.13.0.jar"
- "BOOT-INF/lib/jackson-module-parameter-names-2.13.0.jar"
- "BOOT-INF/lib/tomcat-embed-core-9.0.55.jar"
- "BOOT-INF/lib/tomcat-embed-el-9.0.55.jar"
- "BOOT-INF/lib/tomcat-embed-websocket-9.0.55.jar"
- "BOOT-INF/lib/spring-web-5.3.13.jar"
- "BOOT-INF/lib/spring-beans-5.3.13.jar"
- "BOOT-INF/lib/spring-webmvc-5.3.13.jar"
- "BOOT-INF/lib/spring-expression-5.3.13.jar"
- "BOOT-INF/lib/spring-aop-5.3.13.jar"
- "BOOT-INF/lib/spring-security-config-5.6.0.jar"
- "BOOT-INF/lib/spring-security-web-5.6.0.jar"
- "BOOT-INF/lib/aspectjweaver-1.9.7.jar"
- "BOOT-INF/lib/HikariCP-4.0.3.jar"
- "BOOT-INF/lib/spring-jdbc-5.3.13.jar"
- "BOOT-INF/lib/jakarta.transaction-api-1.3.3.jar"
- "BOOT-INF/lib/jakarta.persistence-api-2.2.3.jar"
- "BOOT-INF/lib/hibernate-core-5.6.1.Final.jar"
- "BOOT-INF/lib/jboss-logging-3.4.2.Final.jar"
- "BOOT-INF/lib/byte-buddy-1.11.22.jar"
- "BOOT-INF/lib/antlr-2.7.7.jar"
- "BOOT-INF/lib/jandex-2.2.3.Final.jar"
- "BOOT-INF/lib/classmate-1.5.1.jar"
- "BOOT-INF/lib/hibernate-commons-annotations-5.1.2.Final.jar"
- "BOOT-INF/lib/jaxb-runtime-2.3.5.jar"
- "BOOT-INF/lib/txw2-2.3.5.jar"
- "BOOT-INF/lib/istack-commons-runtime-3.0.12.jar"
- "BOOT-INF/lib/jakarta.activation-1.2.2.jar"
- "BOOT-INF/lib/spring-data-jpa-2.6.0.jar"
- "BOOT-INF/lib/spring-data-commons-2.6.0.jar"
- "BOOT-INF/lib/spring-orm-5.3.13.jar"
- "BOOT-INF/lib/spring-tx-5.3.13.jar"
- "BOOT-INF/lib/slf4j-api-1.7.32.jar"
- "BOOT-INF/lib/spring-aspects-5.3.13.jar"
- "BOOT-INF/lib/spring-boot-actuator-autoconfigure-2.6.1.jar"
- "BOOT-INF/lib/spring-boot-actuator-2.6.1.jar"
- "BOOT-INF/lib/micrometer-core-1.8.0.jar"
- "BOOT-INF/lib/HdrHistogram-2.1.12.jar"
- "BOOT-INF/lib/LatencyUtils-2.0.3.jar"
- "BOOT-INF/lib/log4j-slf4j-impl-2.14.1.jar"
- "BOOT-INF/lib/log4j-api-2.14.1.jar"
- "BOOT-INF/lib/log4j-core-2.14.1.jar"
- "BOOT-INF/lib/log4j-jul-2.14.1.jar"
- "BOOT-INF/lib/jul-to-slf4j-1.7.32.jar"
- "BOOT-INF/lib/jackson-module-kotlin-2.13.4.jar"
- "BOOT-INF/lib/jackson-databind-2.13.0.jar"
- "BOOT-INF/lib/jackson-annotations-2.13.0.jar"
- "BOOT-INF/lib/jackson-datatype-jsr310-2.13.4.jar"
- "BOOT-INF/lib/jackson-core-2.13.0.jar"
- "BOOT-INF/lib/kotlin-reflect-1.7.10.jar"
- "BOOT-INF/lib/kotlin-stdlib-1.7.10.jar"
- "BOOT-INF/lib/kotlin-stdlib-common-1.7.10.jar"
- "BOOT-INF/lib/annotations-13.0.jar"
- "BOOT-INF/lib/kotlin-stdlib-jdk8-1.7.10.jar"
- "BOOT-INF/lib/kotlin-stdlib-jdk7-1.7.10.jar"
- "BOOT-INF/lib/jjwt-0.9.1.jar"
- "BOOT-INF/lib/jjwt-api-0.11.5.jar"
- "BOOT-INF/lib/validation-api-2.0.1.Final.jar"
- "BOOT-INF/lib/passay-1.6.2.jar"
- "BOOT-INF/lib/h2-1.4.200.jar"
- "BOOT-INF/lib/mysql-connector-java-8.0.27.jar"
- "BOOT-INF/lib/jakarta.xml.bind-api-2.3.3.jar"
- "BOOT-INF/lib/jakarta.activation-api-1.2.2.jar"
- "BOOT-INF/lib/spring-security-core-5.6.0.jar"
- "BOOT-INF/lib/spring-security-crypto-5.6.0.jar"
- "BOOT-INF/lib/spring-boot-jarmode-layertools-2.6.1.jar"

@ -0,0 +1,10 @@
- "dependencies":
- "BOOT-INF/lib/"
- "spring-boot-loader":
- "org/"
- "snapshot-dependencies":
- "application":
- "BOOT-INF/classes/"
- "BOOT-INF/classpath.idx"
- "BOOT-INF/layers.idx"
- "META-INF/"

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save