Как зайти в Даркнет?!
25th January, 01:11
4
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
893
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
912
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4380
0
Помогите пожалуйста решить задачи
24th November, 23:53
6084
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4350
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4395
0
Метода Крамера С++
23rd October, 11:55
4308
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2598
0
Почему плохой пароль вызывает "заполнение недопустимо и не может быть удалено"?
Мне нужно было какое-то простое строковое шифрование, поэтому я написал следующий код (с большим количеством "inspiration" отсюда ):
// create and initialize a crypto algorithm
private static SymmetricAlgorithm getAlgorithm(string password) {
SymmetricAlgorithm algorithm = Rijndael.Create();
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
password, new byte[] {
0x53,0x6f,0x64,0x69,0x75,0x6d,0x20, // salty goodness
0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
}
);
algorithm.Padding = PaddingMode.ISO10126;
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
/*
* encryptString
* provides simple encryption of a string, with a given password
*/
public static string encryptString(string clearText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
/*
* decryptString
* provides simple decryption of a string, with a given password
*/
public static string decryptString(string cipherText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] cipherBytes = Convert.FromBase64String(cipherText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
Код, похоже, работает нормально, за исключением того, что при расшифровке данных с неверным ключом я получаю CryptographicException - "Padding is invalid and cannot be removed" - на строке cs.Close() в decryptString.
пример кода:
string password1 = "password";
string password2 = "letmein";
string startClearText = "The quick brown fox jumps over the lazy dog";
string cipherText = encryptString(startClearText, password1);
string endClearText = decryptString(cipherText, password2); // exception thrown
Мой вопрос в том, можно ли этого ожидать? Я бы подумал, что расшифровка с неверным паролем просто приведет к бессмысленному выходу, а не к исключению.
Хотя на этот вопрос уже был дан ответ, я думаю, что было бы неплохо объяснить, почему этого следует ожидать.
Обычно применяется схема заполнения, поскольку большинство криптографических фильтров не являются семантически безопасными и предотвращают некоторые формы криптотаксов. Например, обычно в RSA используется схема заполнения OAEP , которая предотвращает некоторые виды атак (такие как выбранная атака открытого текста или ослепление ).
Схема заполнения добавляет некоторый (обычно) случайный мусор к сообщению m перед отправкой сообщения. Например, в методе OAEP используются два Оракула (это упрощенное объяснение):
- Учитывая размер модуля, вы набираете K1 бит с 0 и K0 бит со случайным числом.
- Затем, применяя некоторое преобразование к сообщению, вы получаете дополненное сообщение, которое шифруется и отправляется.
Это дает вам рандомизацию для сообщений и способ проверить, является ли сообщение мусором или нет. Поскольку схема заполнения обратима, когда вы расшифровываете сообщение, в то время как вы ничего не можете сказать о целостности самого сообщения, Вы можете фактически сделать некоторое утверждение о заполнении, и таким образом вы можете знать, правильно ли было расшифровано сообщение или вы делаете что-то неправильно (т. е. кто-то подделал сообщение или вы используете неправильный ключ)
Я испытал подобное исключение "Padding is invalid and cannot be removed.", но в моем случае ключ IV и заполнение были правильными.
Оказалось, что промывка криптопотока - это все, чего не хватало.
Подобный этому:
MemoryStream msr3 = new MemoryStream();
CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write);
encStream.Write(bar2, 0, bar2.Length);
// unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding
encStream.FlushFinalBlock();
byte[] bar3 = msr3.ToArray();
Если вы хотите, чтобы ваше использование было правильным, Вы должны добавить аутентификацию к вашему шифртексту, чтобы вы могли проверить, что это правильный пароль или что шифртекст не был изменен. Заполнение, которое вы используете ISO10126 , вызовет исключение только в том случае, если последний байт не расшифровывается как одно из 16 допустимых значений для заполнения (0x01-0x10). Таким образом, у вас есть 1/16 шанс того, что он NOT выбрасывает исключение с неверным паролем, где, если вы аутентифицируете его, у вас есть детерминированный способ определить, является ли ваша расшифровка действительной.
Использование crypto api хотя и кажется простым, на самом деле довольно легко совершать ошибки. Например, вы используете фиксированную соль для вашего ключа и IV деривации, это означает, что каждый зашифрованный шифр с одним и тем же паролем будет повторно использовать его IV с этим ключом, что нарушает семантическую безопасность в режиме CBC, IV должен быть одновременно непредсказуемым и уникальным для данного ключа.
По этой причине легко ошибиться, у меня есть фрагмент кода, который я стараюсь держать пересмотренным и актуальным (комментарии, вопросы приветствуются):
Современные примеры симметричного аутентифицированного шифрования строки C#.
Если вы используете его AESThenHMAC.AesSimpleDecryptWithPassword(ciphertext, password) , когда используется неправильный пароль, null возвращается, если шифртекст или iv был изменен после шифрования null возвращается, вы никогда не получите ненужные данные или исключение заполнения.
Если вы исключили ключевое несоответствие, то, кроме FlushFinalBlock() (см. ответ Янива), достаточно также вызвать Close() на CryptoStream .
Если вы очищаете ресурсы строго с блоками using , обязательно вложите блок для самого CryptoStream :
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
{
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
} // implicit close
byte[] encArray = ms.ToArray();
}
Я был укушен этим (или подобным):
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
byte[] encArray = ms.ToArray();
} // implicit close -- too late!
Другой причиной исключения может быть состояние гонки между несколькими потоками, использующими логику расшифровки-собственные реализации ICryptoTransform не являются потокобезопасными (например, SymmetricAlgorithm), поэтому его следует поместить в раздел exclusive, например, используя блокировку . Пожалуйста, обратитесь сюда для получения более подробной информации: http://www.make-awesome.com/2011/07/system-security-cryptography-and-thread-safety/