> To save the future you have to look at the past. Someone from the > inside sent you an access code to a bank account with a lot of > money. Can you handle the past and decrypt the code to save the > future? The challenge consists of a source code and program output file, with the twist being that it's a COBOL program doing crypto: identification division. program-id. otp. environment division. input-output section. file-control. select key-file assign to 'key.txt' organization line sequential. data division. file section. fd key-file. 01 key-data pic x(50). working-storage section. 01 ws-flag pic x(1). 01 ws-key pic x(50). 01 ws-parse. 05 ws-parse-data pic S9(9). 01 ws-xor-len pic 9(1) value 1. 77 ws-ctr pic 9(1). procedure division. open input key-file. read key-file into ws-key end-read. display 'Enter your message to encrypt:'. move 1 to ws-ctr. perform 50 times call 'getchar' end-call move return-code to ws-parse move ws-parse to ws-flag call 'CBL_XOR' using ws-key(ws-ctr:1) ws-flag by value ws-xor-len end-call display ws-flag with no advancing add 1 to ws-ctr end-add end-perform. cleanup. close key-file. goback. end program otp. I happen to have studied a few tutorials for that language, so translation of the main procedure to equivalent Ruby code wasn't too hard: key = open(key_file, &:read) ctr = 1 50.times do flag = getchar flag[ctr] ^= key[ctr] print flag ctr += 1 end Curiously enough this looks like a proper OTP implementation, so the devil must be lurking somewhere else. I have never understood COBOL storage instructions, so instead of poring over comically verbose documentation I opted for compiling the program instead. Using `cobc -x -o otp otp.cob` and suitable input and key files I've tried it out myself and noticed a troubling pattern, the output characters form a repeating pattern of 10 characters! Looking at the code again the culprit is the following line: 77 ws-ctr pic 9(1). Who would have guessed that programming languages allowing you to restrict integer types to arbitrary ranges are a thing. How underhanded! This bug reduces the crypto involved to breaking repeating key XOR, something I've done twice so far for Cryptopals. Plugging in my old code didn't work though since the ciphertext is laughably short and doesn't quite resemble English, so a slightly different approach is required. The cryptography term for a short piece of known plaintext is crib. According to a team mate the flag format is `flag{1337_shit}`, so `flag{` is an obvious one to look for. The idea is to XOR the crib into a specific position of the ciphertext to obtain a piece of the keystream, deriving the key resulting in the same keystream, creating a new keystream from that key and performing a partial decryption of the ciphertext using it. This way a bigger part of the plaintext can be obtained and with a bit of luck, a slightly bigger crib. The process can be repeated until a crib of 10 characters or the whole plaintext has been guessed. My script automates it with all possible offsets, so after a dozen iterations one of the printed strings was: flag{N0w_u_c4n_buy_CO2_c3rts_&_s4v3_th3_fUtUrE1!}