FinCrypt is a hybrid cryptosystem utilizing ECIES, ECDSA, AES-256, and SHA3-512. FinCrypt was written by me over the course of about 2 weeks, and went through many iterations before it solidified as it's current form.
FinCrypt started out as a joke. It was originally a minified and slightly obfuscated pure RSA implementation. Insecure and horrible as it was, it still managed to properly encrypt and decrypt using RSA, but it had many flaws. The lack of OAEP, the plaintext message length left inside a message, and other flaws killed it's cryptographic security.
Eventually, a simple change to the message to integer function allowed for the message length to not be sent in cleartext. However, OAEP was still nowhere to be seen and thus the cryptosystem could be classified as textbook RSA.
I then noticed that the encryption and decryption times for FinCrypt were obscenely long, due to using 4096 bit keys and encrypting the entire message with RSA. I decided to move FinCrypt to a hybrid system, and immediately set my sights on an AES-256 system, likely in CBC mode. However, a readable, pure Python implementation of AES-256 was hard to come by, but I eventually found one by Richard Moore. Changing the body of my encryption methods was a simple step from there. It was also at this point that I added RSA signing.
Even though FinCrypt was now a fully functional hybrid cryptosystem, I was unhappy with the rather simplistic message and key format of writing numbers in plaintext with delimiters. Thus, the only external dependency was added to FinCrypt. ASN.1 was an obvious choice given strong Python support, but my usual implementation was too big to stick in a single file and thus include transparently in FinCrypt. I thought about this for a while, and then decided that the ASN.1 was not really essential to decryption, and was thus excusable to include a dependency, even though it is much less easy for a beginner to find and read the source code for.
FinCrypt, however, still lacked many convenience factors for sending keys, such as error correction when typing a key in, and QR code generation. QR code generation was easy, a single import and a few lines of code. However, error correction was much more difficult. I eventually settled on Reed-Solomon error correction with 30 error correction bytes in a 255 byte block, thus allowing for up to 15 accidental changes in a byte before the error correcting algorithm would be unable to correct the data any further. However, Base64 encoding can still result in uncorrectable errors, due to byte boundaries not lining up, padding, and other causes.
OAEP was still something that FinCrypt lacked, and I decided to implement it using SHAKE256, to allow for arbitrary length input data. This, however, required a minor addition to the SHA module, and thus I embarked on an internet search session to discover the specific padding function used by the SHAKE family of extendable output hash functions. Thankfully, the answer was painfully easy to find, requiring only a visit to the Keccak Team's documentation. Thus, OAEP was easy to implement and makes it virtually impossible to decrypt the plaintext without decrypting every single block and bit in the AES encrypted FinCrypt message. Even a single change in the input to the OAEP unpadding functions has a massive and unpredictable effect on the output, rendering a brute force for keys much more difficult.
To be continued...