Ответ 1
Я предполагаю, что CTS и CBC всегда будут иметь одинаковый результат, если входной сигнал составляет 8 бит. Неужели это просто удача или совпадение или в основном истина?
Нет, это ложное утверждение.
Вот цитата из Википедии:
Шифрование в Ciphertext для режима CBC необязательно требует, чтобы открытый текст был длиннее одного блока. В случае, когда открытым текстом является один блок длинным или меньшим, вектор инициализации (IV) может выступать в качестве предыдущего блока зашифрованного текста.
Таким образом, даже для вашего случая с 8-байтовым входом, CTS-алгоритм вступает в игру и влияет на выход. В основном ваше выражение о равенстве CTS и CBS может быть отменено:
CTS и CBC всегда будут иметь одинаковый результат до двух последних блоков.
Вы можете проверить его с помощью следующего образца:
static byte[] EncryptData(byte[] input, string algorithm)
{
IBufferedCipher inCipher = CipherUtilities.GetCipher(algorithm);
var hashOfPrivateKey = HashValue(Encoding.ASCII.GetBytes("12345678"));
var key = new KeyParameter(hashOfPrivateKey);
var IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
var cipherParams = new ParametersWithIV(key, IV);
inCipher.Init(true, cipherParams);
return inCipher.DoFinal(input);
}
static void Main(string[] args)
{
var data = Encoding.ASCII.GetBytes("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF");
var ctsResult = EncryptData(data, "BLOWFISH/CTS");
var cbcResult = EncryptData(data, "BLOWFISH/CBC");
var equalPartLength = data.Length - 2 * 8;
var equal = ctsResult.Take(equalPartLength).SequenceEqual(cbcResult.Take(equalPartLength));
}
Так что это в основном ответ на ваш главный вопрос. Вы не должны ожидать того же выхода для CTS и CBC на 8-байтовом входе.
Вот ответы (надеюсь) на ваши другие вопросы:
Если режим CTS, используемый в Delphi Encryption Compendium, использует CBC вместе с CTS. Я не мог найти документально нигде.
Я не нашел никакой документации для режима CTS в Delphi Encryption Compendium, но есть такие комментарии в исходном коде:
cmCTSx = двойной CBC, с заполнением CFS8 усеченного финального блока
Режимы cmCTSx, cmCFSx, cmCFS8 - это разработанные мной фирменные режимы. Эти режимы работают, например, cmCBCx, cmCFBx, cmCFB8, но с двойным XOR'ing входного потока в регистр обратной связи.
Похоже, что режим CTS реализован по-своему в Delphi Encryption Compendium, который не будет совместим со стандартной реализацией Bouncy Castle.
Разница между вызовом только DoFinal() и ProcessBytes(), а затем DoFinal() в Bouncy Castle, я полагаю, что это необходимо, когда входной блок больше размера блока двигателя, в этом случае они одного размера.
Для шифрования данных требуется пара вызовов ProcessBytes()
/DoFinal()
. Это может потребоваться, например, при передаче огромных данных. Однако, если у вас есть подпрограмма, которая принимает весь массив байтов для шифрования, вы можете просто вызвать следующую удобную перегрузку DoFinal()
один раз:
var encryptedData = inCipher.DoFinal(plainText);
Эта перегрузка DoFinal()
будет вычислять размер выходного буфера и делать необходимые вызовы ProcessBytes()
и DoFinal()
под капотом.
Если Delphi Encryption Compendium является правильным/неправильным или если Bouncy Castle является правильным/неправильным. У меня недостаточно знаний в криптографии, чтобы понять реализацию, иначе я не стал бы задавать вопрос здесь (мне нужно руководство).
Подведем итог:
- Вы не должны ожидать того же выхода для CTS и CBC для 8-байтового ввода.
- Похоже, что Delphi Encryption Compendium использует собственный алгоритм для CTS. Поскольку Bouncy Castle реализован в соответствии со стандартами, эти библиотеки будут давать разные результаты. Если ваше новое приложение не требуется для поддержки зашифрованных данных, созданных с помощью устаревшего приложения Delphi, вы можете просто использовать Bouncy Castle и быть в порядке. В другом случае вы должны использовать тот же пользовательский алгоритм CTS, который использует Delphi Encryption Compendium, к которому, к сожалению, потребуется порт его источников для С#.
ОБНОВИТЬ
(Более подробная информация о реализации компендиума Delphi Encryption в версии 3.0)
Вот код кодирования CTS из DEC версии 3.0:
S := @Source;
D := @Dest;
// ...
begin
while DataSize >= FBufSize do
begin
XORBuffers(S, FFeedback, FBufSize, D);
Encode(D);
XORBuffers(D, FFeedback, FBufSize, FFeedback);
Inc(S, FBufSize);
Inc(D, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(S, FBuffer, DataSize, D);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
Здесь мы видим двойной XOR'ing, упомянутый в документации DEC. В основном этот код реализует следующий алгоритм:
C[i] = Encrypt( P[i] xor F[i-1] )
F[i] = F[i-1] xor C[i]
F[0] = IV
тогда как стандартный алгоритм будет:
C[i] = Encrypt( P[i] xor C[i-1] )
C[0] = IV
Шаг F[i] = F[i-1] xor C[i]
является авторским изобретением DEC и делает результаты шифрования различными. Обработка последних двух блоков, которая имеет решающее значение для режима CTS, также реализуется не стандартом.
Вот комментарий от DEC v 3.0 ReadMe.txt, который описывает, почему автор добавил такую модификацию:
cmCTS Mode, XOR Данные до и теперь после шифрования. Это улучшает Securityeffect при использовании InitVector, выход защищен при использовании плохого InitVector, около 1% потери скорости
Это очень распространенная ошибка, когда авторы библиотек безопасности пытаются сделать базовые алгоритмы "более безопасными" такими наивными модификациями. Во многих случаях такие изменения имеют обратный эффект и уменьшают прочность защиты. Другим недостатком, конечно же, является то, что зашифрованные данные не могут быть расшифрованы другими библиотеками, реализованными в соответствии со стандартом, например, в вашем случае.