Commit 7dc5e904 authored by Vincent Ehrmanntraut's avatar Vincent Ehrmanntraut

Initial commit

parents
Pipeline #258 failed with stages
in 0 seconds
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
#
# VincCTF 2018 - Agency 1
from random import randint
import base64
import click
sbox = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
permutation1 = []
permutation2 = []
permutation3 = []
i = 0
j1 = 0
j2 = 0
j3 = 0
def generate_permutation(key):
result = [0 for i in range(256)]
for i in range(256):
a = i
b = key
for r in range(3):
a = sbox[a ^ (b & 0xFF)]
b >>= 8
result[i] = a
return result
def key_schedule(key, iv):
global permutation1
global permutation2
global permutation3
permutation1 = generate_permutation(int(key[0:6], 16))
permutation2 = generate_permutation(int(key[6:12], 16))
permutation3 = generate_permutation(iv)
def swap(list, a, b):
x = list[a]
list[a] = list[b]
list[b] = x
def next_byte():
global i
global j1
global j2
global j3
i = (i + 1) % 256
j1 = (j1 + permutation1[i]) % 256
j2 = (j2 + permutation2[i]) % 256
j3 = (j3 + permutation3[i]) % 256
swap(permutation1, i, j1)
swap(permutation2, i, j2)
swap(permutation3, i, j3)
return permutation1[permutation1[i] ^ permutation1[j1]] ^ \
permutation2[permutation2[i] ^ permutation2[j2]] ^ \
permutation3[permutation3[i] ^ permutation3[j3]]
def encrypt_data(key, data):
# Random iv to prevent (Key, iv)-reuse
iv = randint(0, 2**24)
key_schedule(key, iv)
enc = "".join(chr(ord(x) ^ next_byte()) for x in data)
return str(iv) + '|' + base64.b64encode(enc)
def decrypt_data(key, data):
parts = data.split('|')
iv = int(parts[0])
decoded = base64.b64decode(parts[1])
key_schedule(key, iv)
return "".join(chr(ord(x) ^ next_byte()) for x in decoded)
# Setup the cli arguments
@click.command(context_settings = dict(help_option_names = ['-h', '--help']))
@click.option('-e', '--encrypt', is_flag = True, default = False, help = 'Encrypt a string')
@click.option('-d', '--decrypt', is_flag = True, default = False, help = 'Decrypt a string')
def main(encrypt, decrypt):
"""The ultimately secure stream cipher made by Agency(TM)"""
# Encrypt
if encrypt:
key = click.prompt('Key')
plaintext = click.prompt('Your data')
click.echo(encrypt_data(key, plaintext))
elif decrypt:
key = click.prompt('Key')
ciphertext = click.prompt('Your data')
click.echo(decrypt_data(key, ciphertext))
# No option given
else:
click.secho('No option selected. See -h/--help for more information', fg = 'yellow', bold = True)
raise click.Abort
if __name__ == '__main__':
main()
## Agency 1
### Description
The agency has published a new cipher and a python implementation. We intercepted two messages knowing that one of them is "I can't believe we finally managed to get this stuff working!". Can you decrypt the other?
Message 1: 10777675|L4aWT0CSKc/2sINvH5RBAaAQ5RSMOC0bhBpZnjBMjwHGTJpI
Message 2: 11266551|Q/sNhwC5Y7dxsqW4Lj33UTm/O5rETY7fJBnZ8uQwHY7A13v2cVF9Dyk0JLNekI0BX5h9vpe7F7lFpZ5G1g==
### Spoilers
Flag: `VINCCTF{X0r1nG_sTr3Am5_mu5t_b3_s4F3}`
\ No newline at end of file
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
from random import randint
import base64
import click
# Variables
knownMsgCiphertext = 'Q/sNhwC5Y7dxsqW4Lj33UTm/O5rETY7fJBnZ8uQwHY7A13v2cVF9Dyk0JLNekI0BX5h9vpe7F7lFpZ5G1g=='
knownMsgPlaintext = "I can't believe we finally managed to get this stuff working!"
knownMsgIv = 11266551
flagMsgCiphertext = 'L4aWT0CSKc/2sINvH5RBAaAQ5RSMOC0bhBpZnjBMjwHGTJpI'
flagMsgIv = 10777675
Sbox = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
permutation1 = []
permutation2 = []
i = 0
j1 = 0
j2 = 0
def generate_permutation(key):
result = [0 for i in range(256)]
for i in range(256):
a = i
b = key
for r in range(3):
a = Sbox[a ^ (b & 0xFF)]
b >>= 8
result[i] = a
return result
def swap(list, a, b):
x = list[a]
list[a] = list[b]
list[b] = x
def next_byte():
global i
global j1
global j2
i = (i + 1) % 256
j1 = (j1 + permutation1[i]) % 256
j2 = (j2 + permutation2[i]) % 256
swap(permutation1, i, j1)
swap(permutation2, i, j2)
return permutation1[permutation1[i] ^ permutation1[j1]] ^ \
permutation2[permutation2[i] ^ permutation2[j2]]
def xor_strings(xs, ys):
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys))
def main():
global permutation1
global permutation2
permutation1 = generate_permutation(knownMsgIv)
permutation2 = generate_permutation(flagMsgIv)
# Xor the known message with both iv-streams
# tmp = (m0 ^ k ^ iv0) ^ (iv0 ^ iv1) = m0 ^ k ^ iv1
decoded = base64.b64decode(knownMsgCiphertext)
tmp = "".join(chr(ord(x) ^ next_byte()) for x in decoded)
# Xor tmp with the known message so tmp becomes the complete keystream for c1
# tmp = (m0 ^ k ^ iv1) ^ m0 = k ^ iv1
tmp = xor_strings(tmp, knownMsgPlaintext)
# Decrypt the flag
# flag = c1 ^ tmp = (m1 ^ k ^ iv1) ^ (k ^ iv1) = m1
flag = xor_strings(tmp, base64.b64decode(flagMsgCiphertext))
print 'Flag: ' + flag
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
#
# VincCTF 2018 - Agency 2
from random import randint
import base64
import click
Sbox = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
permutation1 = []
permutation2 = []
permutation3 = []
i = 0
j1 = 0
j2 = 0
j3 = 0
def generate_permutation(key, rounds):
result = [0 for i in range(256)]
for i in range(256):
a = i
b = key
for r in range(rounds):
a = Sbox[a ^ (b & 0xFF)]
b >>= 8
result[i] = a
return result
def key_schedule(key, iv):
global permutation1
global permutation2
global permutation3
permutation1 = generate_permutation(int(key[0:8], 16), 4)
permutation2 = generate_permutation(int(key[8:12], 16), 2)
permutation3 = generate_permutation(iv, 3)
def swap(list, a, b):
x = list[a]
list[a] = list[b]
list[b] = x
def next_byte():
global i
global j1
global j2
global j3
i = (i + 1) % 256
j1 = (j1 + permutation1[i]) % 256
j2 = (j3 + permutation2[i]) % 256
j3 = (j2 + permutation3[i]) % 256
swap(permutation1, i, j1)
swap(permutation2, i, j2)
swap(permutation3, i, j3)
return permutation1[permutation1[i] ^ permutation1[j1]] ^ \
permutation2[permutation2[i] ^ permutation2[j2]] ^ \
permutation3[permutation3[i] ^ permutation3[j3]]
def encryptData(key, data):
# Random iv to prevent (Key, iv)-reuse
iv = randint(0, 2**24)
key_schedule(key, iv)
enc = "".join(chr(ord(x) ^ next_byte()) for x in data)
return str(iv) + '|' + base64.b64encode(enc)
def decryptData(key, data):
parts = data.split('|')
iv = int(parts[0])
decoded = base64.b64decode(parts[1])
key_schedule(key, iv)
return "".join(chr(ord(x) ^ next_byte()) for x in decoded)
# Setup the cli arguments
@click.command(context_settings = dict(help_option_names = ['-h', '--help']))
@click.option('-e', '--encrypt', is_flag = True, default = False, help = 'Encrypt a string')
@click.option('-d', '--decrypt', is_flag = True, default = False, help = 'Decrypt a string')
def main(encrypt, decrypt):
"""The ultimatively secure stream cipher made by Agency(TM)"""
# Encrypt
if encrypt:
key = click.prompt('Key')
plaintext = click.prompt('Your data')
click.echo(encryptData(key, plaintext))
elif decrypt:
key = click.prompt('Key')
ciphertext = click.prompt('Your data')
click.echo(decryptData(key, ciphertext))
# No option given
else:
click.secho('No option selected. See -h/--help for more information', fg = 'yellow', bold = True)
raise click.Abort
if __name__ == '__main__':
main()
\ No newline at end of file
## Agency
### Description
The agency apparently watched the CTF and hotfixed their cipher. To test the their security, we encrypted two messages, one containing the flag, the other one states "Congratulations, this text was encrypted using the updated cutting-edge cipher by the Agency."
Message one: 11779216|lML8xptbk6PNw6OJnwTvGCjQX2wzyRjiSAU7t+B0zB08uNAmp53IrWSM0ipVlvn2Nw==
Message two: 7723444|MyYnnIlfXV9GENIJCHc90EXFidGA9bTNr89Kf8irRBS0HGFK+EEJON72hYLuC6wv+KaikYfEiO5hk8qO6JQCHE6M6gOzbls0jPWCae0bJJ88rN68SabHxghyL9pJ
### Spoiler
Flag: `VINCCTF{N0t_b4cKD0Or3d_jUst_V4ri1nG_P3rMut4t1ons}`
\ No newline at end of file
from random import randint
import base64
KNOWN_DATA = "Congratulations, this text was encrypted using the updated cutting-edge cipher by the Agency."
KNOWN_DATA_CIPHERTEXT = "MyYnnIlfXV9GENIJCHc90EXFidGA9bTNr89Kf8irRBS0HGFK+EEJON72hYLuC6wv+KaikYfEiO5hk8qO6JQCHE6M6gOzbls0jPWCae0bJJ88rN68SabHxghyL9pJ"
KNOWN_DATA_IV = 7723444
FLAG_CIPHERTEXT = "lML8xptbk6PNw6OJnwTvGCjQX2wzyRjiSAU7t+B0zB08uNAmp53IrWSM0ipVlvn2Nw=="
FLAG_IV = 11779216
Sbox = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
permutation1 = []
permutation2 = []
permutation3 = []
i = 0
j1 = 0
j2 = 0
j3 = 0
def generate_permutation(key, rounds):
result = [0 for i in range(256)]
for i in range(256):
a = i
b = key
for r in range(rounds):
a = Sbox[a ^ (b & 0xFF)]
b >>= 8
result[i] = a
return result
def key_schedule(key, iv):
global permutation1
global permutation2
global permutation3
permutation1 = generate_permutation(int(key[0:8], 16), 4)
permutation2 = generate_permutation(int(key[8:12], 16), 2)
permutation3 = generate_permutation(iv, 3)
def swap(list, a, b):
x = list[a]
list[a] = list[b]
list[b] = x
def next_byte():
global i
global j1
global j2
global j3
i = (i + 1) % 256
j1 = (j1 + permutation1[i]) % 256
j2 = (j3 + permutation2[i]) % 256
j3 = (j2 + permutation3[i]) % 256
swap(permutation1, i, j1)
swap(permutation2, i, j2)
swap(permutation3, i, j3)
return permutation1[permutation1[i] ^ permutation1[j1]] ^ \
permutation2[permutation2[i] ^ permutation2[j2]] ^ \
permutation3[permutation3[i] ^ permutation3[j3]]
def encryptData(key, data):
# Random iv to prevent (Key, iv)-reuse
iv = randint(0, 2**24)
key_schedule(key, iv)
enc = "".join(chr(ord(x) ^ next_byte()) for x in data)
return str(iv) + '|' + base64.b64encode(enc)
def decryptData(key, data):
parts = data.split('|')
iv = int(parts[0])
decoded = base64.b64decode(parts[1])
key_schedule(key, iv)
return "".join(chr(ord(x) ^ next_byte()) for x in decoded)
def decrypt_key2_iv_stream(data, perm2, perm3):
result = ""
i = 0
tmp2 = 0
tmp3 = 0
for c in data:
i = (i + 1) % 256
tmp2 = (tmp3 + perm2[i]) % 256
tmp3 = (tmp2 + perm3[i]) % 256
swap(perm2, i, tmp2)
swap(perm3, i, tmp3)
result += chr(ord(c) ^ perm2[perm2[i] ^ perm2[tmp2]] ^ perm3[perm3[i] ^ perm3[tmp3]])
return result
def xor_stream(data, key, iv):
p1 = generate_permutation(key, 2)
p2 = generate_permutation(iv, 3)
i = 0
j1 = 0
j2 = 0
result = ''
for x in data:
i = (i + 1) % 256
j1 = (j2 + p1[i]) % 256
j2 = (j1 + p2[i]) % 256
swap(p1, i, j1)
swap(p2, i, j2)
result += chr(ord(x) ^ p1[p1[i] ^ p1[j1]] ^ p2[p2[i] ^ p2[j2]])
return result
def xor_strings(xs, ys):
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys))
def run():
know_keystream = xor_strings(KNOWN_DATA, base64.b64decode(KNOWN_DATA_CIPHERTEXT))
decoded_flag_ciphertext = base64.b64decode(FLAG_CIPHERTEXT)
for i in xrange(2**16):
tmp = decrypt_key2_iv_stream(know_keystream, generate_permutation(i, 2), generate_permutation(KNOWN_DATA_IV, 3))
tmp = decrypt_key2_iv_stream(tmp, generate_permutation(i, 2), generate_permutation(FLAG_IV, 3))
flag = xor_strings(tmp, decoded_flag_ciphertext)
if flag[0:4] == "VINC":
print "Found possilbe flag: " + flag
if (i & 1023) == 0:
print i
if __name__ == '__main__':
run()
\ No newline at end of file
#!/usr/bin/env python2
#-*- coding:utf-8 -*-
#
# VincCTF 2018 - Agency 3
from base64 import b64encode, b64decode
from hashlib import sha256
from random import randint
import click
from utils.edutils import public_key, scalarmultKeyInt, addKeys
base_point = public_key(123456)
state = None
additional_info = None
def init(key, nonce):
global state
global additional_info
x = int(sha256(key + str(nonce)).hexdigest(), base=16)
state = scalarmultKeyInt(base_point, x)
additional_info = public_key(x)
def iterate():
global state
state = addKeys(state, base_point)
return state[0:16]
def xor_strings(xs, ys):
return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys))
def encrypt_data(msg, key):
nonce = randint(0, 2**24)
init(key, nonce)
result = ''
remaining = len(msg)
while remaining > 0:
print remaining
x = min(remaining, 16)
result += xor_strings(msg[0:x], iterate()[0:x])
msg = msg[x:]
remaining -= x
return str(nonce) + '|' + additional_info + '|' + b64encode(result)
def decrypt_data(msg, key):
parts = msg.split('|')
nonce = int(parts[0])
msg = b64decode(parts[2])
init(key, nonce)
result = ''
remaining = len(msg)
while remaining > 0:
x = min(remaining, 16)
result += xor_strings(msg[0:x], iterate()[0:x])
msg = msg[x:]
remaining -= x
return result
# Setup the cli arguments
@click.command(context_settings = dict(help_option_names = ['-h', '--help']))
@click.option('-e', '--encrypt', is_flag = True, default = False, help = 'Encrypt a string')
@click.option('-d', '--decrypt', is_flag = True, default = False, help = 'Decrypt a string')
def main(encrypt, decrypt):
"""The ultimately secure stream cipher made by Agency(TM)"""
# Encrypt
if encrypt:
key = click.prompt('Key')
plaintext = click.prompt('Your data')
click.echo(encrypt_data(plaintext, key))
elif decrypt:
key = click.prompt('Key')
ciphertext = click.prompt('Your data')
click.echo(decrypt_data(ciphertext, key))
# No option given
else:
click.secho('No option selected. See -h/--help for more information', fg = 'yellow', bold = True)
raise click.Abort