На оф.форуме выложил код небольшой прожки с GUI.
Ранее я писал это на AutoIt3, просто переписал на PureBasic в связи с поднятием темы шифрования на оф.форуме.
Из нового, в AutoIt3 была функция с паролем, а тут надо было пароль 16 байт и вектор 16 байт, пришлось писать функцию, которая имеет неявный пароль генерируемый рандомом с RandomSeed, а поверх "рандома" писать пароль из поля в GUI, если будет не хватать длины, она будет дополнена "рандомом" до 16 байт. Перечитал справку, 16 байт для 128 битного ключа, так что мне надо либо битность исправить, либо увеличить ключ, но это уже мелочи, при тесте всё работает как есть.
Кодировать / декодировать файл
Сообщений 1 страница 30 из 46
Поделиться118.04.2025 02:35:36
Поделиться218.04.2025 13:11:03
На оф.форуме выложил код небольшой прожки с GUI.
Файл читается целиком в память. Если он имеет большой объем может не получится выделить столько памяти. Лучше читать частями, скажем по 10 МБ и выполнять шифрование функциями StartAESCipher(), AddCipherBuffer() и FinishCipher().
Из нового, в AutoIt3 была функция с паролем, а тут надо было пароль 16 байт и вектор 16 байт, пришлось писать функцию, которая имеет неявный пароль генерируемый рандомом с RandomSeed, а поверх "рандома" писать пароль из поля в GUI
Я не знаю как устроен AES в AutoIt3. Может он работает в режиме Electronic CodeBook при котором InitializationVector не требуется, но качество шифрования ниже.
С паролем можно сделать так.
Без InitializationVector
UseSHA1Fingerprint() ; Шифруем строку String$ = "Здравствуйте, это тест для AES" Pass.s = "1234" ; Пароль шифрования. StringMemorySize = StringByteLength(String$) + SizeOf(Character) *CipheredString = AllocateMemory(StringMemorySize) *DecipheredString = AllocateMemory(StringMemorySize) *Key = Ascii(StringFingerprint(Pass, #PB_Cipher_SHA1, 0, #PB_Unicode)) ShowMemoryViewer(*Key, MemorySize(*Key)) If AESEncoder(@String$, *CipheredString, StringByteLength(String$), *Key, 256, 0, #PB_Cipher_ECB) Debug "Ciphered: "+PeekS(*CipheredString) ; Предупреждение, это остановится на первом нулевом байте, только для демонстрации. AESDecoder(*CipheredString, *DecipheredString, StringByteLength(String$), *Key, 256, 0, #PB_Cipher_ECB) Debug "Deciphered: "+PeekS(*DecipheredString) EndIf FreeMemory(*CipheredString) FreeMemory(*DecipheredString) FreeMemory(*Key)
С InitializationVector
UseSHA1Fingerprint() UseMD5Fingerprint() ; Шифруем строку String$ = "Здравствуйте, это тест для AES" Pass.s = "1234" ; Пароль шифрования. StringMemorySize = StringByteLength(String$) + SizeOf(Character) *CipheredString = AllocateMemory(StringMemorySize) *DecipheredString = AllocateMemory(StringMemorySize) *Key = Ascii(StringFingerprint(Pass, #PB_Cipher_SHA1, 0, #PB_Unicode)) *InitializationVector = Ascii(StringFingerprint(Pass, #PB_Cipher_MD5, 0, #PB_Unicode)) If AESEncoder(@String$, *CipheredString, StringByteLength(String$), *Key, 256, *InitializationVector, #PB_Cipher_CBC) Debug "Ciphered: "+PeekS(*CipheredString) ; Предупреждение, это остановится на первом нулевом байте, только для демонстрации. AESDecoder(*CipheredString, *DecipheredString, StringByteLength(String$), *Key, 256, *InitializationVector, #PB_Cipher_CBC) Debug "Deciphered: "+PeekS(*DecipheredString) EndIf FreeMemory(*CipheredString) FreeMemory(*DecipheredString) FreeMemory(*Key) FreeMemory(*InitializationVector)
Здесь используется ascii строка хеша, а лучше перевести в бинарные данные, заменив SHA1 на SHA2 или SHA3 с 256 битным результатом.
Поделиться318.04.2025 17:27:38
Пётр
С SHA3 более проще. Была идея, если открыть путь, то зашифровать все файлы в папке. И добавить поддержку ком.строки, чтобы в конт.меню проводника можно было добавить. Про открывать блоками я знал, в AutoIt3 так и делал, но для MD5.
Поделиться418.04.2025 18:25:27
Чем вас не устроил "Исключающее или"?! Там можно для каждого файла гонять ключ в виде файла и получать результат.
Поделиться518.04.2025 18:37:46
У Aes уровень шифрования выше.
Поделиться618.04.2025 21:24:26
InputFile$=OpenFileRequester("Выберите файл для шифровки/дешифровки.","","",0) InputFile=ReadFile(#PB_Any,InputFile$) If InputFile=0:End:EndIf KeyFile$=OpenFileRequester("Выберите файл-ключ.","","",0) KeyFile=ReadFile(#PB_Any,KeyFile$) If KeyFile=0:End:EndIf *Key.Ascii=AllocateMemory(Lof(KeyFile)) If ReadData(KeyFile,*Key,Lof(KeyFile))<>Lof(KeyFile):End:EndIf OutputFile$=SaveFileRequester("Выберите файл-результат.","","",0) OutputFile=CreateFile(#PB_Any,OutputFile$) If OutputFile=0:End:EndIf *k.Ascii=*Key *Overflow=*k+Lof(KeyFile) While Eof(InputFile)=0 WriteAsciiCharacter(OutputFile,ReadAsciiCharacter(InputFile)!*k\a) *k+SizeOf(Ascii) If *k=*Overflow:*k=*Key:EndIf Wend
Не знаю... Что-то подобное я уже писал, вот и набросал то чё помню. Принцип простой, но для ключа надо выделять память. Можно конечно и из файла напрямую читать и бегать до начала файла, но так-быстрее.
Поделиться718.04.2025 21:28:00
"Исключающее или"?!
Я и так знал, что степень защищенности максимальная, даже закон у нас есть проги шифрования с ключом не выше 128, иначе даже супер комп не расшифрует. Так на хабре статья, что шифрование блоками и предыдущий блок содержит ключ возможно вектор это и есть он для следующего блока, то есть не имея какой то части невозможно расшифровать последующее. Исключающее или это уровень детсада.
Поделиться818.04.2025 21:56:28
Зато можно просто выбрать входной файл, выбрать файл-ключ например изображение(щёлкнуть "фотку") и ей шифрануть чё хочешь. Работает же, Там даже больше уровня детского сада - если размер ключа равен размеру входного файла.
Поделиться919.04.2025 12:17:39
ReadFile(0,OpenFileRequester("Select input.","","",0)) ReadFile(1,OpenFileRequester("Select key.","","",0)) CreateFile(2,SaveFileRequester("Select output.","","",0)) While Eof(0)=0 WriteAsciiCharacter(2,ReadAsciiCharacter(0)!ReadAsciiCharacter(1)) If Eof(1)=0:FileSeek(1,0):EndIf:Wend
С минимальным потреблением памяти то есть ключ-файл быть может любой длины. Всё зависит только от накопителя и его размера. Сам воспользовался и не пожалел.
Поделиться1019.04.2025 13:20:36
Зато можно просто выбрать входной файл, выбрать файл-ключ например изображение(щёлкнуть "фотку") и ей шифрануть чё хочешь. Работает же, Там даже больше уровня детского сада - если размер ключа равен размеру входного файла.
Если используется XOR и и известна начальная последовательность байтов(для PNG/JPG), то можно вычислить и ключ и все такое.
Поделиться1119.04.2025 18:24:47
Ну попробуй вычисли. Я щёлкни две фотки - одна истинная, вторая-ключ и пришлю тебе зашифрованный файл, а ты мне вышли результат который у меня истинный чтобы он совпал.
Отредактировано PSY (19.04.2025 18:25:35)
Поделиться1219.04.2025 19:34:40
PSY
Ну не будете же вы с собой картинку таскать, теряется весь смысл пароля.
Поделиться1319.04.2025 19:48:34
А если у меня много изображений то я могу просто знать какое из них - ключ. Или Музыка и видео. Кто мешает это использовать во качестве ключа.
Поделиться1419.04.2025 20:22:39
Ну попробуй вычисли. Я щёлкни две фотки - одна истинная, вторая-ключ и пришлю тебе зашифрованный файл, а ты мне вышли результат который у меня истинный чтобы он совпал.
Больно ты нужен что-то доказывать.
Поделиться1519.04.2025 23:31:29
egons
Его вариант реальный, так как текстовая книга будет максимум 2 Мб, а тут на неё "картинку наложи" размером 4 Мб. По смыслу получится как шифровка, с разницей что каждый символ будет свой собственный, даже "а" в позиции 5 и "а" в позиции 15 будет ни одним и тем же символом, тут даже повторений не будет. Одно случайное число "сольётся" с другим случайным числом. По сути каждая буква-позиция имеет свой код. Нет даже алгоритма расшифровки такого.
Только алгоритм, который мы обсуждаем имеет короткий пароль, а метод с картинкой это необходимость иметь картинку.
Отредактировано AZJIO (19.04.2025 23:35:12)
Поделиться1620.04.2025 06:33:02
Его вариант реальный, так как текстовая книга будет максимум 2 Мб, а тут на неё "картинку наложи" размером 4 Мб.
Объясните мне, скудоумному, на кой ляд понадобились такие громадные картинки с громадными ключами шифрования?
Поделиться1720.04.2025 12:18:49
Ну дык можно вообще использовать не только изображение во качестве ключа шифровки/расшифровки, а можно даже выбрать что угодно, даже какой-нибудь фильм или любой файл. Смысл исключающего ИЛИ в самом надёжном варианте - это размер ключа равен размеру входных данных или размер ключа более размера входных данных. Тогда результат шифрования - будет очень надёжным.
Отредактировано PSY (20.04.2025 12:19:20)
Поделиться1820.04.2025 12:25:42
Пётр
Сделал чтение по 10 Мб.
Обновление
Добавлена командная строка, для добавления программы в контекстное меню файлового менеджера.
Добавлено шифрование блоками по 10 Мб, не загружая весь файл в память.
Изменён формат ключа - хеш-сумма, вместо генерации байтов.
Исходник для Linux пока от предыдущей версии
Поделиться1920.04.2025 15:05:11
Исключающее или это уровень детсада
Шифрование - интересная тема, но и опасная тоже. Поиграешь с ним, а потом получается программа шифрования, после которой и сам уже не знаешь, как расшифровать текст, или бинарный файл, не зная входных параметров для шифрования.
И главное, даже зная, как я его зашифровал с несложным алгоритмом, потом сложно придумать алгоритм расшифровки, который бы даже на суперкомпьютере расшифровал бы полученный результат, потому что и для брутфорса нужно же с чем-нибудь сравнивать - получилась ли расшифровка в текущем варианте.
Так вот, играя с шифрованием можно получить результат, который потом какой-нибудь гад сможет использовать для злых дел. А ты только и сможешь потом рассказать свой алгоритм шифрования, а как расшифровать такую переписку, или такие файлы, и сам не придумаешь.
Тем более, что без проблем ведь в такой программе шифрования поставить еще один параметр: количество циклов шифрования. И все. На что тут потом натравливать суперкомпьютер для расшифровки, с чем ему сравнивать полученные переборы вариантов - всё равно получается сплошная бинарная каша и довольно равномерная. А если знаешь входные параметры для шифрования - то секунда работы, и текст/файл расшифрован.
Интересная тема, но похожая на изготовление чего-то опасного. Как у тех физиков в 30-е годах, которым было просто интересно, получится ли у них самоподдерживающаяся реакция расщепления атомов. Получилась. То-то обрадовались этому потом жители Хиросимы.
Отредактировано Nemo3001 (20.04.2025 15:27:55)
Поделиться2020.04.2025 15:14:34
Не увидел в коде функцию FinishCipher(), а должна быть.
Все же лучше переводить строку в бинарный вид о чем я писал выше. Это увеличит стойкость шифрования.
Сейчас в ключе и векторе могут быть только цифры от 0 до 9 и буквы от a до f.
UseMD5Fingerprint() MD5.s = StringFingerprint("1234", #PB_Cipher_MD5, 0, #PB_Unicode) Debug MD5 *MD5 = Ascii(MD5) ShowMemoryViewer(*MD5, MemorySize(*MD5))
В бинарном виде будет весь диапазон значений байта - 0 - 255.
UseMD5Fingerprint() Procedure HexToBin(s.s) Protected *Point=0, Pos=0, i, Count Count = Len(s) If Count > 0 If Count % 2 <> 0 : Debug "Не кратно 2!!!! Возможна запись за пределы выделенной памяти!!!!" : EndIf *Point = AllocateMemory(Count / 2) If *Point For i=1 To Count Step 2 PokeA(*Point+Pos, Val("$"+Mid(s, i, 2))) Pos+1 Next EndIf EndIf ProcedureReturn *Point EndProcedure MD5.s = StringFingerprint("1234", #PB_Cipher_MD5, 0, #PB_Unicode) Debug MD5 *MD5 = HexToBin(MD5) ShowMemoryViewer(*MD5, MemorySize(*MD5))
Поделиться2120.04.2025 18:05:42
Не увидел в коде функцию FinishCipher(), а должна быть.
Я так увлёкся победой, что просто забыл про неё.
HexToBin
а у меня уже есть её аналог BinaryHex() с посимвольным разбором (средняя), только там поменять нужно для шестнадцатеричных нижнего регистра.
#PB_Cipher_MD5 возвращает длину 18, #PB_Cipher_SHA3 - 34, даже в этом случае хватает только на пароль, а вектор либо дублировать пароль, либо ещё что-то придумывать (34 * 8 = 272).
Перезалил с исправлениями.
Отредактировано AZJIO (20.04.2025 19:02:40)
Поделиться2220.04.2025 19:05:36
#PB_Cipher_MD5 возвращает длину 18
16 байт (128 бит).
#PB_Cipher_SHA3 - 34
32 байта (256 бит).
UseMD5Fingerprint() UseSHA2Fingerprint() Procedure HexToBin(s.s) Protected *Point=0, Pos=0, i, Count Count = Len(s) If Count > 0 If Count % 2 <> 0 : Debug "Не кратно 2!!!! Возможна запись за пределы выделенной памяти!!!!" : EndIf *Point = AllocateMemory(Count / 2) If *Point For i=1 To Count Step 2 PokeA(*Point+Pos, Val("$"+Mid(s, i, 2))) Pos+1 Next EndIf EndIf ProcedureReturn *Point EndProcedure MD5.s = StringFingerprint("1234", #PB_Cipher_MD5, 0, #PB_Unicode) Debug MD5 *MD5 = HexToBin(MD5) ShowMemoryViewer(*MD5, MemorySize(*MD5)) Debug "MD5 Size="+MemorySize(*MD5) FreeMemory(*MD5) SHA.s = StringFingerprint("1234", #PB_Cipher_SHA2, 256, #PB_Unicode) Debug SHA *SHA = HexToBin(SHA) ShowMemoryViewer(*SHA, MemorySize(*SHA)) Debug "SHA2 256 bit Size="+MemorySize(*SHA) FreeMemory(*SHA)
*SHA использовать как ключ, а *MD5 как вектор.
Размер соответствует AES 256 бит.
Поделиться2320.04.2025 19:12:53
а *MD5 как вектор
Вектор тоже должен быть 32 байта для 256-битного. Если на винде работает укороченный, но на линукс я сразу получал ошибку и временно вставлял 128 бит, чтобы работало с 16.
Кстати, мне понравился пример от wilbert, где получение символа из бинарного представления без использования Chr()
Вот, сделал адаптацию
EnableExplicit Structure CharStr StructureUnion c.c s.s{1} EndStructureUnion EndStructure Procedure BinaryHex(String$) Protected *m, *r.Ascii, *c.CharStr Protected tmp.s{3} Protected Size If Not Asc(String$) ; пустая строка ProcedureReturn -1 EndIf Size = Len(String$) If Size & 1 ; нечётное число ProcedureReturn -2 EndIf *c = @String$ *m = AllocateMemory(Size / 2 + 2) If *m *r = *m ; 0-9 и a-f (только в нижнем регистре) While (*c\c > 47 And *c\c < 58) Or (*c\c > 96 And *c\c < 103) ; Or (*c\c > 64 And *c\c < 71) ; A-F верхний регистр не берём во внимание tmp = "$" tmp + *c\s *c + 2 If *c\c tmp + *c\s *r\a = Val(tmp) *r + 1 *c + 2 Else ; повторная проверка чётности, нужна ли она FreeMemory(*m) ProcedureReturn -3 EndIf Wend ; проверка дошли ли мы до конца строки, если не 0, ; то не дошли и в строке есть не шестнадцатеричные символы If *c\c <> 0 ProcedureReturn -4 EndIf If *r > *m *r\a = 0 ; Добавляем ещё 0, чтобы можно было использовать UTF8, UTF16 *r + 1 *r\a = 0 EndIf EndIf ProcedureReturn *m EndProcedure UseSHA3Fingerprint() Define *s, *u, tmp$ ; tmp$ = StringFingerprint("1234", #PB_Cipher_MD5, 0, #PB_Unicode) tmp$ = StringFingerprint("1234", #PB_Cipher_SHA3, 256, #PB_Unicode) ; Debug Len(tmp$) Debug tmp$ *s = BinaryHex(tmp$) Debug MemorySize(*s) If *s > 0 ShowMemoryViewer(*s, MemorySize(*s) - 1) ; Debug PeekS(*s, -1, #PB_Ascii) ; Ascii ; Debug PeekS(*s) ; UTF8 FreeMemory(*s) EndIf
Отредактировано AZJIO (20.04.2025 19:58:56)
Поделиться2420.04.2025 21:09:10
Вектор тоже должен быть 32 байта для 256-битного.
Тогда в справке ошибка https://www.purebasic.com/documentation … coder.html
*InitializationVector The InitializationVector is a random data block, used to initialize the ciphering to avoid breach in decoding (only needed when using the #PB_Cipher_CBC mode). Its size is always 16 bytes long. The contents of this data block must match the one which was used when encoding the data.
Проверил на вируталке, и ошибки не было.
Вот, сделал адаптацию
Размер должен быть 32 байта. Где в строке хеша есть нулевые байты?
Завершающие строку нулевые байты не имеют отношения к содержимому строки.
Поделиться2520.04.2025 21:59:44
Тогда в справке ошибка
В CHM версии 6.20 всё норм.
*InitializationVector The InitializationVector is a random data block, used to initialize the ciphering to avoid breach in decoding (only needed when using the #PB_Cipher_CBC mode). Its size depends of the 'Bits' parameter: 16 bytes for 128-bit encryption, 24 bytes for 196-bit and 32 bytes for 256-bit.
Проверил на вируталке, и ошибки не было.
Возможно это был пароль, так как я изменил 256 на 128 в функции шифрования. Иначе бы мне пришлось переписывать функцию GetKey() где было больше телодвижений. Так если для вектора исправлено, так может и раньше это было просто ошибка справки.
Где в строке хеша есть нулевые байты?
ок, урежу, хотя они не попадают, так как берётся всё равно 32 байта.
Ну вообще-то это ShowMemoryViewer() возвращает из-за MemorySize(), а AllocateMemory() выделяет на 2 байта больше, чтобы данные завершились нультерминированной строкой и их без проблем можно было прочитать с помощью PeekS(). Так что может не стоит заморачиваться с этим...
Отредактировано AZJIO (20.04.2025 22:17:45)
Поделиться2620.04.2025 22:39:47
В CHM версии 6.20 всё норм.
В справке 6.20 тоже что в олнайн справке.
Поделиться2720.04.2025 23:11:15
Пётр
Я использовал из StartAESCipher(), так как он и в коде у меня, там именно так.
Поделиться2821.04.2025 00:03:37
Тогда 256 битный SHA2 для ключа и 256 битный SHA3 для вектора или наоборот. Можно также сгенерировать ключ и/или вектор функцией DeriveCipherKey().
Поделиться2923.04.2025 19:59:31
Пётр
Собственно функция DeriveCipherKey() создана специально для этого:
If Not DeriveCipherKey(Pass$, Pass$, 5, *Key, 512, #PB_Cipher_SHA3, 512) ProcedureReturn EndIf *InitializationVector = *Key + 32
InitializationVector можно было бы создать с помощью DeriveCipherKey() с другим числом итераций, дабы не добавлять модуль MD5, но при наличии ключа 512 проще взять по пол-ключа.
Но DeriveCipherKey() не дал бы использовать прогу на WinXP, а так как я хочу пока поддерживать её, то сделал имитацию DeriveCipherKey()
For i = 0 To 2 ; трёх кратный хеш пароля, вот она итерация Pass$ = StringFingerprint(Pass$, #PB_Cipher_SHA3, 512, #PB_Unicode) Next *Key = BinaryHex(Pass$) ; не бинарный? Делаем бинарный If Not *Key ProcedureReturn EndIf *InitializationVector = *Key + 32
Перезалил
Отредактировано AZJIO (23.04.2025 22:03:26)
Поделиться3024.04.2025 10:56:42
Объясните мне, скудоумному, на кой ляд понадобились такие громадные картинки с громадными ключами шифрования?
Паранойя
Похожие темы
WebGadget и картинка | Вопросы по PureBasic | 20.02.2025 |