Answer the question
In order to leave comments, you need to log in
C# How to encrypt a file?
Hello!
There is a file that needs to be encrypted using the permutation key method. I make a key-value pair (Dictionary), where the key is the letter of the key, the value is a List of bytes. The problem is that for the integrity of the picture it is necessary that the number of bytes be a multiple of the number of characters in the key. I can't figure out how to add zeros to the beginning of the file.
An example of my encryption code for text:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace coding_encoding
{
class Crypto
{
private string key;
private char[] temp;
public Crypto(string key)
{
this.key = key;
temp = this.key.ToCharArray();
Array.Sort(temp);
}
/// <summary>
/// Метод, позволяющий расшифровать строку по ключу.
/// </summary>
/// <param name="message">Строка, которую нужно расшифровать.</param>
/// <param name="key">Ключ, по которому будет производиться расшифровка.</param>
/// <returns>Расшифрованная строка.</returns>
public string Decrypt(string message)
{
string sortedKey = string.Empty;
string result = string.Empty;
Dictionary<int, char> dictionaryIntChar = new Dictionary<int, char>();
Dictionary<char, List<char>> keyValuePairs;
Dictionary<char, List<char>> resultDictionary = new Dictionary<char, List<char>>();
for (int i = 0; i < key.Length; i++)
dictionaryIntChar[i] = key[i];
foreach (char ch in temp)
sortedKey += ch;
//здесь идет добавление символа для кратности
while (message.Length % key.Length != 0)
message += " ";
keyValuePairs = GetDictionary(message, sortedKey);
for (int i = 0; i < key.Length; i++)
{
for (int j = i; j < message.Length; j += key.Length)
{
resultDictionary[dictionaryIntChar[i]] = keyValuePairs[dictionaryIntChar[i]];
}
}
//компановка полученного сообщения
return Composition(key.ToCharArray(), resultDictionary);
}
/// <summary>
/// Метод, позволяющий зашифровать строку по ключу.
/// </summary>
/// <param name="message">Строка, которую нужно зашифровать.</param>
/// <param name="key">Ключ, по которому будет производиться шифрование.</param>
/// <returns>Зашифрованная строка.</returns>
public string Encrypt(string message)
{
Dictionary<char, List<char>> keyValuePairs;
string result = string.Empty;
//добавляем в строку пустые символы для сохранения целостности столбцов
while (message.Length % key.Length != 0)
message += " ";
keyValuePairs = GetDictionary(message, key);
//компановка полученного сообщения
return Composition(temp, keyValuePairs);
}
/// <summary>
/// Компановка полученного сообщения.
/// </summary>
/// <param name="editKey">Массив из букв ключа.</param>
/// <param name="keyValuePairs">Словарь ключ-значение</param>
/// <returns>Скомпонованное сообщение.</returns>
private string Composition(char[] editKey, Dictionary<char, List<char>> keyValuePairs)
{
string result = string.Empty;
for (int i = 0; i < keyValuePairs[editKey[0]].Count; i++)
for (int j = 0; j < editKey.Length; j++)
result += keyValuePairs[editKey[j]][i].ToString();
return result;
}
/// <summary>
/// Получение словаря ключ-значение.
/// </summary>
/// <param name="message">Сообщение, которое нужно привязать к буквам ключа</param>
/// <param name="key">Буквы ключа, к которым будет привязываться сообщение</param>
/// <returns>Словарь</returns>
private Dictionary<char, List<char>> GetDictionary(string message, string key)
{
Dictionary<char, List<char>> result = new Dictionary<char, List<char>>();
for (int i = 0; i < key.Length; i++)
{
List<char> listChar = new List<char>();
//добавление символов столбца ключу
for (int j = i; j < message.Length; j += key.Length)
{
listChar.Add(message[j]);
}
//связывание ключ-значение
result.Add(key[i], listChar);
}
return result;
}
}
}
Answer the question
In order to leave comments, you need to log in
To be honest, I don't quite understand what the problem is. If the file is not too big, you can read it into memory with File.ReadAllText, then encode the content and write it to another file. If the file is large, then you can use FileStream - the logic changes a little, but it's also nothing complicated.
I've optimized your code for strings a bit:
class Crypto2
{
private readonly int[] _key;
private readonly int[] _inversedKey;
public Crypto2(string key)
{
var indexPairs = key
.Select((chr, idx1) => new { chr, idx1 }) // присваиваем каждому символу индекс
.OrderBy(arg => arg.chr) // сортируем по символам
.Select((arg, idx2) => new { arg.idx1, idx2 }) // и теперь создаём массив из пар "первоначальный индекс" <=> "отсортированный индекс".
.ToArray();
// Генерируем прямой ключ: чем "меньше" символ (в алфавитном порядке), тем меньше его индекс в конечном массиве.
// "а" => 0, ... , "ь" => 5
// Получаем: "цезарь" => [4, 1, 2, 0, 3, 5]
_key = indexPairs
.OrderBy(arg => arg.idx1)
.Select(arg => arg.idx2)
.ToArray();
// Обратная операция для декодирования
_inversedKey = indexPairs
.OrderBy(arg => arg.idx2)
.Select(arg => arg.idx1)
.ToArray();
}
public string Encrypt(string message)
{
return EncryptDecrypt(message, _key);
}
public string Decrypt(string message)
{
return EncryptDecrypt(message, _inversedKey);
}
private static string EncryptDecrypt(string message, int[] key)
{
var keyLength = key.Length;
var messageLength = message.Length;
if (messageLength % keyLength > 0)
{
// Дополняем строку пробелами, если необходимо
message = message.PadRight(messageLength + keyLength - messageLength % keyLength, ' ');
}
// Никогда не используйте конкатенацию строк в цикле (типа result += keyValuePairs[editKey[j]][i].ToString();). Это очень медленно.
// Для этих целей есть специальный класс StringBuilder.
// Мы заранее знаем длину конечной строки, поэтому инициализируем StringBuilder правильно.
var sb = new StringBuilder(messageLength) {Length = message.Length};
for (var i = 0; i < message.Length; i++)
{
// Вычисляем конечный индекс для вставки символа.
// Первая часть выражения "i / keyLength * keyLength" - округление i вниз до ближайшего значения, делящегося на keyLength
// Вторая часть "key[i % keyLength]" - вычисление новой позиции символа на основе ключа.
var idx = i / keyLength * keyLength + key[i % keyLength];
sb[idx] = message[i];
}
return sb.ToString();
}
}
class Crypto3
{
private readonly int[] _key;
private readonly int[] _inversedKey;
public Crypto3(string key)
{
var indexPairs = key
.Select((chr, idx1) => new {chr, idx1})
.OrderBy(arg => arg.chr)
.Select((arg, idx2) =>
new
{
arg.idx1, idx2
})
.ToArray();
_key = indexPairs
.OrderBy(arg => arg.idx1)
.Select(arg => arg.idx2)
.ToArray();
_inversedKey = indexPairs
.OrderBy(arg => arg.idx2)
.Select(arg => arg.idx1)
.ToArray();
}
public void Encrypt(string sourceFile, string destinationFile)
{
EncryptDecrypt(sourceFile, destinationFile, _key);
}
public void Decrypt(string sourceFile, string destinationFile)
{
EncryptDecrypt(sourceFile, destinationFile, _inversedKey);
}
private static void EncryptDecrypt(string sourceFile, string destinationFile, int[] key)
{
var keyLength = key.Length;
var buffer1 = new byte[keyLength];
var buffer2 = new byte[keyLength];
using (var source = new FileStream(sourceFile, FileMode.Open))
using (var destination = new FileStream(destinationFile, FileMode.OpenOrCreate))
{
while (true)
{
var read = source.Read(buffer1, 0, keyLength);
if (read == 0)
{
return;
}
else if (read < keyLength)
{
for (int i = read; i < keyLength; i++)
{
buffer1[i] = (byte) ' ';
}
}
for (var i = 0; i < keyLength; i++)
{
var idx = i / keyLength * keyLength + key[i % keyLength];
buffer2[idx] = buffer1[i];
}
destination.Write(buffer2, 0, keyLength);
}
}
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question