Most of the logic doesn't matter in the end. The only thing that matters is the following two facts:
1. The flag is encrypted using `key2`2. After every call to `encrypt()`, the value of `key2` is updated to be the resulting ciphertext
After spending some time reading the code these two points became apparent, and then it was simply a matter of getting the encrypted flag twice in a row and using the first encrypted flag as the key to decrypt the second one. Most of the time ended up being implementing a decrypt, as you can see in the following code:
See link for details.