I'd have one objection: the Readme doesn't say anything about the underlying primitives (are you using something standard or did you invent your own cipher?), and doesn't say anything about external validation (are you alone so far, or did your code get reviewed?). If it's a learning exercise, warning wannabe users would be nice.
That said, your code looks too simple not to be easily breakable. I'm no expert, but that piqued my interest. I'll take a look. If I break it, I'll write an article about it.
Okay, I think I have cracked it. Haven't tested it, but a qualitative reasoning should be enough to get you going.
I concentrated my efforts on your Cape::encrypt() method. Inlining Cape::crypt() and simplifying the resulting code gives something like this (it appears some computations cancelled each other):
void Cape::encrypt(char *source, char *destination, uint8_t length)
{
uint8_t iv = this->generate_IV();
char real_key[255];
for (i = 0; i < _key_length; i++)
real_key[i] = _key[(i ^ _reduced_key) % _key_length];
for (i = 0; i < length; i++)
destination[i] = source[i] ^ iv ^ i ^ real_key[i];
destination[length] = iv ^ _reduced_key;
};
Now the weaknesses of your algorithm are clear.
First, I don't believe your IV is truly randomly generated. I don't know of a real CSPRNG on Arduino, so… probably not your fault.
Second, your IV is only one byte. You cannot securely send more than 256 messages with the same key.
Third, the attacker can get rid of the IV anyway: since it is given at the end of the ciphertext, I can just XOR it with the rest of the ciphertext before trying to crack it. This makes your IV irrelevant. You are now limited to one message per key. In practical terms, you don't do better than a one time pad.
Fourth, the way you access the key in a weird order doesn't matter. It's the same as using a different key. Assuming your key is properly unpredictable in the first place, there is no need to access it in a weird order. I made this clear by reordering the key in a real_key.
Fifth, XORing the message with the index doesn't buy you anything: the attacker will just reverse it before trying to crack the rest.
Sixth, if your key is shorter than the message, you have a repeating key. Repeating keys are shown to be broken since… a long time. The reason why is because XORing parts of the ciphertext encoded with the same key reveals the XOR of parts of the plaintext, and that is easily broken in practice. So you're forced to use keys as long as the message.
Conclusion: you have a fancy one time pad. It is secure if your key is as long as the message, and you use it only once. I have to say your home-made crypto is not completely broken. But… a simple one time pad would have achieved the same results more simply.
A word of (dangerous) advice: you won't accomplish much with XOR alone. Modern ciphers tend to also to rearrange the order of the bits as well. If I may, we have a real cryptographer here, and he has written a course: https://www.crypto101.io/
That said, your code looks too simple not to be easily breakable. I'm no expert, but that piqued my interest. I'll take a look. If I break it, I'll write an article about it.