Я пытаюсь расшифровать зашифрованное шифровальщиком шестнадцатеричное сообщение, используя 20-й раунд смешивания IV с ключом MyKey.
Сообщения:
bad85d9e7f5aff959b6b332b44af2cc554d8a6eb
Я делаю это на чистом С#, и он должен вернуть сообщение: Hola Mundo
using System;
using System.Text;
public class Program
{
public static void Main(string[] args)
{
// Hexadecimal text
string hexText = "bad85d9e7f5aff959b6b332b44af2cc554d8a6eb";
// Convert hexadecimal text to byte array
byte[] encryptedData = new byte[hexText.Length / 2];
for (int i = 0; i < encryptedData.Length; i++)
{
encryptedData[i] = Convert.ToByte(hexText.Substring(i * 2, 2), 16);
}
// IV length
int ivLength = 1;
// Key loop iterations
int keyIterations = 20;
// Encryption key
string encryptionKey = "MyKey";
// Convert encryption key to byte array
byte[] keyData = Encoding.UTF8.GetBytes(encryptionKey);
// Create an array to store the IV
byte[] ivData = new byte[ivLength];
// Copy the first `ivLength` bytes of the encrypted data to the IV array
Array.Copy(encryptedData, 0, ivData, 0, ivLength);
// Create an array to store the encrypted message
byte[] messageData = new byte[encryptedData.Length - ivLength];
// Copy the remaining bytes of the encrypted data to the message data array
Array.Copy(encryptedData, ivLength, messageData, 0, messageData.Length);
// Create an array to store the decrypted message
byte[] decryptedData = new byte[messageData.Length];
// Perform the decryption
for (int i = 0; i < messageData.Length; i++)
{
decryptedData[i] = (byte)(messageData[i] ^ keyData[i % keyData.Length]);
for (int j = 0; j < keyIterations; j++)
{
decryptedData[i] = (byte)(decryptedData[i] ^ ivData[j % ivData.Length]);
}
}
// Convert the decrypted data to a string and print it
string decryptedMessage = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("Decrypted message: " + decryptedMessage);
}
}
Теперь, когда я пытаюсь, он возвращает: �$�#���Jf=�I���
Какую ошибку я делаю в коде или неправильно его реализую?
Я проверил текст на следующем сайте, чтобы убедиться, что он в порядке: https://ruletheweb.co.uk/cgi-bin/saber.cgi
CipherSaber использует в качестве IV первые 10 байт зашифрованного сообщения. Остальное - настоящий зашифрованный текст. IV добавляется к ключу (предоставляя ввод для настройки ключа), который используется в качестве ввода для настройки ключа CipherSaber, см. CipherSaber, Техническое описание, 1-й раздел.
В опубликованном коде применяется длина IV, равная 1, вместо 10, что неверно определяет IV (и, следовательно, ввод настройки ключа) и фактический зашифрованный текст. Правильное определение IV и фактического зашифрованного текста:
private static (byte[], byte[]) SeparateIvCiphertext(byte[] ivCiphertext)
{
int ivLen = 10;
byte[] iv = new byte[ivLen];
Buffer.BlockCopy(ivCiphertext, 0, iv, 0, iv.Length);
byte[] ciphertext = new byte[ivCiphertext.Length - iv.Length];
Buffer.BlockCopy(ivCiphertext, iv.Length, ciphertext, 0, ciphertext.Length);
return (iv, ciphertext);
}
И ключевого ввода настройки:
private static byte[] GetKeySetupInput(byte[] key, byte[] iv)
{
byte[] keySetupInput = new byte[key.Length + iv.Length];
Buffer.BlockCopy(key, 0, keySetupInput, 0, key.Length);
Buffer.BlockCopy(iv, 0, keySetupInput, key.Length, iv.Length);
return keySetupInput;
}
Кроме того, само расшифрование, по-видимому, реализовано неправильно или, по крайней мере, не полностью. CipherSaber использует RC4 в качестве алгоритма шифрования/дешифрования, который можно разделить на настройку ключа и фактическое шифрование/дешифрование:
Упомянутый веб-сайт выполняет расшифровку с использованием CipherSaber-2. По сравнению с исходным CipherSaber (называемым CipherSaber-1) используется модифицированная настройка ключа, в которой настройка ключа CipherSaber-1/RC4 повторяется несколько раз, 20 раз в случае публикуемых данных. Описание настройки ключа CipherSaber-1/RC4 можно найти здесь, Алгоритм планирования ключей (KSA), возможная реализация для CipherSaber-2:
private static byte[] sBox = new byte[256];
private static void KeySetup(byte[] input, int iterations)
{
for (int i = 0; i < 256; i++)
{
sBox[i] = (byte)i;
}
int j = 0;
for (int cs2loop = 0; cs2loop < iterations; cs2loop++) // CipherSaber-2 modification
{
for (int i = 0; i < 256; i++)
{
j = (j + sBox[i] + input[i % input.Length]) % 256;
Swap(ref sBox[i], ref sBox[j]);
}
}
}
private static void Swap(ref byte val1, ref byte val2)
{
if (val1 == val2) return;
val1 = (byte)(val1 ^ val2);
val2 = (byte)(val2 ^ val1);
val1 = (byte)(val1 ^ val2);
}
Цикл, помеченный модификацией CipherSaber-2 в фрагменте кода, является модификацией по сравнению с CipherSaber-1/RC4!
Фактическое шифрование/дешифрование описано здесь, Алгоритм псевдослучайной генерации (PRGA), возможная реализация:
private static byte[] Process(byte[] input)
{
int i = 0, j = 0;
byte[] result = new byte[input.Length];
for (int k = 0; k < input.Length; k++)
{
i = (i + 1) % 256;
j = (j + sBox[i]) % 256;
Swap(ref sBox[i], ref sBox[j]);
result[k] = (byte)(sBox[(sBox[i] + sBox[j]) % 256] ^ input[k]);
}
return result;
}
Обратите внимание, что этот алгоритм используется как для шифрования, так и для дешифрования.
При этом отправленное зашифрованное сообщение можно расшифровать следующим образом:
using System;
using System.Text;
...
byte[] key = Encoding.UTF8.GetBytes("MyKey");
byte[] encryptedData = Convert.FromHexString("bad85d9e7f5aff959b6b332b44af2cc554d8a6eb");
(byte[] iv, byte[] ciphertext) = SeparateIvCiphertext(encryptedData);
byte[] keySetupInput = GetKeySetupInput(key, iv);
int iterations = 20;
KeySetup(keySetupInput, iterations);
byte[] plaintext = Process(ciphertext);
Console.WriteLine(Encoding.UTF8.GetString(plaintext)); // Hola Mundo
Который дает Hola Mundo в виде открытого текста.
Спасибо, код работает нормально, и теперь я понимаю свою ошибку.
Если я правильно помню, киберсабер основан на RC4. RC4 изменяет ключ при шифровании или расшифровке. Я не вижу, чтобы ваш код делал это.