Нашел много недочетов, но главная ошибка здесь:
char charToEncode = textToEncrypt[charIndex++];
byte[] colorBytes = new byte[] { originalColor.R, originalColor.G, originalColor.B };
for (int i = 0; i < 3; i++)
{
int bitIndex = (bitsPerChannel * i);
if (bitIndex < 8)
{
colorBytes[i] = (byte)((colorBytes[i] & ~1) | ((charToEncode >> bitIndex) & 1));
}
}
Я так полагаю, что символы сообщения кодируются в LSB, но проблема здесь в том, что кодируются только последние 3 бита - остальное (8 - 3 = 5 битов теряются). Т.е. сообщение восстановить никак
+ Сам цикл выглядит очень странно.
Главный вопрос - зачем?
Параметризовать алгоритм стеганографии подобным образом не очень оптимально, т.к. каждый создается с использованием тех или иных фич, который строго захардкожены и используют особенности конкретного формата. Цикл + проверка здесь только ухудшают понимание кода (ИМХО)
Убери этот цикл, т.к. во-первых, станет понятнее, во-вторых, условие внутри при этой константе всегда выполняется.
Теперь про декодирование:
for (int i = 0; i < 3; i++)
{
int bitIndex = (bitsPerChannel * i);
if (bitIndex < 8)
{
charCode |= (byte)((encodedColor.ToArgb() >> bitIndex) & 1);
if (bitIndex <= 2)
{
charCode <<= bitsPerChannel;
}
}
}
Вот этот участок тоже неправильно работает, т.к. ты кодируешь символы в LSB, а читаешь последние 3 бита - из них только 1 бит содержит данные.