Skip to main content

Backpack Cryptography

I love this cryptosystem so much, I carry it everywhere in my backpack. To lighten the load, I make sure I don't pack anything with high densities.

import random
from collections import namedtuple
import gmpy2
from Crypto.Util.number import isPrime, bytes_to_long, inverse, long_to_bytes

FLAG = b'crypto{??????????????????????????}'
PrivateKey = namedtuple("PrivateKey", ['b', 'r', 'q'])

def gen_private_key(size):
s = 10000
b = []
for _ in range(size):
ai = random.randint(s + 1, 2 * s)
assert ai > sum(b)
b.append(ai)
s += ai
while True:
q = random.randint(2 * s, 32 * s)
if isPrime(q):
break
r = random.randint(s, q)
assert q > sum(b)
assert gmpy2.gcd(q,r) == 1
return PrivateKey(b, r, q)


def gen_public_key(private_key: PrivateKey):
a = []
for x in private_key.b:
a.append((private_key.r * x) % private_key.q)
return a


def encrypt(msg, public_key):
assert len(msg) * 8 <= len(public_key)
ct = 0
msg = bytes_to_long(msg)
for bi in public_key:
ct += (msg & 1) * bi
msg >>= 1
return ct


def decrypt(ct, private_key: PrivateKey):
ct = inverse(private_key.r, private_key.q) * ct % private_key.q
msg = 0
for i in range(len(private_key.b) - 1, -1, -1):
if ct >= private_key.b[i]:
msg |= 1 << i
ct -= private_key.b[i]
return long_to_bytes(msg)


private_key = gen_private_key(len(FLAG) * 8)
public_key = gen_public_key(private_key)
encrypted = encrypt(FLAG, public_key)
decrypted = decrypt(encrypted, private_key)
assert decrypted == FLAG

print(f'Public key: {public_key}')
print(f'Encrypted Flag: {encrypted}')

Solution

This blog might help you to solve this problem Lattice or from book Book

This WriteUp Solution is password protected by the flag of the challenge.

After running the script, we get the flag crypto{my_kn4ps4ck_1s_l1ghtw31ght}