
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.52] |
![]() |
|
Сообщ.
#1
,
|
|
|
Подскажите пожалуйста кто сталкивался, если необходимо шифрование алгоритмом AES с помощью CryptoAPI, где именно нужно указывать, что шифрование будет именно этим алгоритмом (необходимо определенный криптопровайдер или определенный тип?)
![]() ![]() CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) Заранее очень благодарен! |
![]() |
Сообщ.
#2
,
|
|
насколько я помню то по умолчанию в винде нет провайдера который работает с AES
|
Сообщ.
#3
,
|
|
|
Цитата mawa @ где именно нужно указывать, что шифрование будет именно этим алгоритмом (необходимо определенный криптопровайдер или определенный тип?) Конкретный алгоритм указывается при создании ключа шифрования, а в CryptAcquireContext нужно указывать имя\тип провайдера, поддерживающего данный алгоритм. Судя по мсдн, AES поддерживается в WinXP и выше провайдером: тип = PROV_RSA_AES, имя = MS_ENH_RSA_AES_PROV |
Сообщ.
#4
,
|
|
|
Спасибо!
Добавлено Я обращаюсь через библиотеку wcrypt2.pas, но в ней нет - PROV_RSA_AES, имеется PROV_RSA_FULL и др. Что делать? |
Сообщ.
#5
,
|
|
|
Объяви сам эту константу. Она равна 24
|
Сообщ.
#6
,
|
|
|
![]() ![]() public { Public declarations } hProv: HCRYPTPROV; key: HCRYPTKEY; encrypt: boolean; end; .... var hProv: HCRYPTPROV; hash: HCRYPTHASH; key: HCRYPTKEY; data: PByte; l: DWORD; fl:boolean; i:integer; err,login,cript_rez: string; cript_temp_1:array[0..65535] of char; cript_temp_2:string[255]; Const PROV_RSA_AES=24; .... {получаем контекст криптопровайдера} CryptAcquireContext(@hProv, nil, nil, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); {создаем хеш-объект} CryptCreateHash(hProv, CALG_SHA, 0, 0, @hash); {хешируем пароль} CryptHashData(hash, @password[1], length(password), 0); {создаем ключ на основании пароля для потокового шифра RC4} CryptDeriveKey(hProv, CALG_RC4, hash, 0, @key); {уничтожаем хеш-объект} CryptDestroyHash(hash); {выделяем место для буфера} GetMem(data, 512); {шифруем данные} login:=text; //данные fl:=true; l:=length(login); for i:=1 to length(login) do begin data^:=ord(login[i]); CryptEncrypt(key, 0, fl, 0, data, @l, l); cript_temp_1[i]:=chr(data^); cript_temp_2[i]:=cript_temp_1[i]; login[i]:=cript_temp_2[i]; //рез-т шифрования end; {освобождаем место и закрываем файлы} FreeMem(data, 512); {освобождаем контекст криптопровайдера} CryptReleaseContext(hProv, 0); Данный код реализован был для шифра RC4, а как для AES сделать? ![]() Добавлено Необходимо указать алгоритм - AES или CALG_AES, а там нет что делать? ![]() ![]() CryptDeriveKey(hProv, CALG_RC4, hash, 0, @key) |
Сообщ.
#7
,
|
|
|
Цитата mawa @ а там нет что делать? Прогуляться по MSDN. Тебе выше ссылку дали. Вот я кликаю по ней, в ней есть еще одна, которая ведет сюда: http://msdn.microsoft.com/en-us/library/aa375545(VS.85).aspx Теперь твоя очередь покликать ![]() ЗЫ: Если снова константа не будет объявлена - объявляй сам. Значение узнать можно в гугле. По запросу "define+имя_константы" находится код, по которому значение и узнается. |
Сообщ.
#9
,
|
|
|
Спасибо!
А вот когда зашифровываю текст, то выдается ошибка 'Unknown error', в чем может быть причина? ![]() ![]() {получаем контекст криптопровайдера} CryptAcquireContext(@hProv, nil, nil, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); {создаем хеш-объект} CryptCreateHash(hProv, CALG_SHA, 0, 0, @hash); {хешируем пароль} CryptHashData(hash, @password[1], length(password), 0); {создаем ключ на основании пароля для AES_256} CryptDeriveKey(hProv,CALG_AES_256,hash,0,@key); .. {выделяем место для буфера} GetMem(data, 512); {шифруем данные} login:=text; //данные fl:=true; l:=length(login); for i:=1 to length(login) do begin data^:=ord(login[i]); if not CryptEncrypt(key, 0, fl, 0, data, @l, l) then begin case int64(GetLastError) of ERROR_INVALID_HANDLE: err := 'ERROR_INVALID_HANDLE'; ERROR_INVALID_PARAMETER: err := 'ERROR_INVALID_PARAMETER'; NTE_BAD_ALGID: err := 'NTE_BAD_ALGID'; NTE_BAD_DATA: err := 'NTE_BAD_DATA'; NTE_BAD_FLAGS: err := 'NTE_BAD_FLAGS'; NTE_BAD_HASH: err := 'NTE_BAD_HASH'; NTE_BAD_HASH_STATE: err := 'NTE_BAD_HASH_STATE'; NTE_BAD_KEY: err := 'NTE_BAD_KEY'; NTE_BAD_LEN: err := 'NTE_BAD_LEN'; NTE_BAD_UID: err := 'NTE_BAD_UID'; NTE_DOUBLE_ENCRYPT: err := 'NTE_DOUBLE_ENCRYPT'; NTE_FAIL: err := 'NTE_FAIL'; NTE_NO_MEMORY: err := 'NTE_NO_MEMORY'; else err := 'Unknown error'; // <-- выдается данное сообщение end; MessageDlg('Error of CryptEncrypt: '+err, mtError, [mbOK], 0); exit; end; cript_temp_1[i]:=chr(data^); cript_temp_2[i]:=cript_temp_1[i]; login[i]:=cript_temp_2[i]; //рез-т шифрования |
Сообщ.
#10
,
|
|
|
Попробуй получить описание ошибки через FormatMessage
![]() ![]() var e:cardinal; mbuf:array[0..511] of char; begin ... e:=GetLastError; case e of ... else begin FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,nil,e,0,mbuf,sizeof(mbuf),nil); err:=IntToStr(e)+#13#10+mbuf; end; |
Сообщ.
#11
,
|
|
|
![]() ![]() else err := 'Unknown error'; заменить на ![]() ![]() else RaiseLastOSError; |
Сообщ.
#12
,
|
|
|
ERROR CRYPTENCRYPT -- Unknown error
Добавлено CodeMonkey System Error. Code:234. Имеются дополнительные данные. Process stopped/ Use step or run to continue/ Добавлено leo Error of CryptEncrypt : 21 Устройство не готово |
Сообщ.
#13
,
|
|
|
Цитата mawa @ Имеются дополнительные данные. Значит 512 - мало. Добавлено По идее, надо как-то так: ![]() ![]() var login: String; X, Y: Integer; ... // вход: login - данные для шифрования // Шаг 1: определяем, сколько надо байт для хранения зашифрованного текста X := Length(login); if not CryptEncrypt(key, 0, True, 0, Pointer(login), X, Length(login)) then if GetLastError <> ERROR_MORE_DATA then RaiseLastOSError; // Шаг 2: выделили буфер (уже не 512, а ровно, сколько надо) Y := Length(login); SetLength(login, X); // Шаг 3: шифрование if not CryptEncrypt(key, 0, True, 0, Pointer(login), Y, Length(login)) then RaiseLastOSError; SetLength(login, Y); // выход: login - зашифрованные данные Писал на коленке, могут быть описки. |
Сообщ.
#14
,
|
|
|
Шифрование вроде работает, по крайней мере получается билиберда, но нужно было :
![]() ![]() if not CryptEncrypt(key, 0, True, 0, Pointer(login), @X, Length(login)) then //@X А вот на расшифровывание ругается, пишит плохие данные : ![]() ![]() login:=z_text; X := Length(login); if not CryptDecrypt(key, 0, True, 0, Pointer(login), @X) then if GetLastError <> ERROR_MORE_DATA then RaiseLastOSError; Y := Length(login); SetLength(login, X); if not CryptDecrypt(key, 0, True, 0, Pointer(login), @Y) then RaiseLastOSError; SetLength(login, Y); |
Сообщ.
#15
,
|
|
|
А дешифровка делается в один шаг. Не надо узнавать размер буфера: исходный текст всегда меньше размером. А вы в своём коде просто откусили от зашифрованного текста кусок и удивляетесь, а чего ж это он ругается на неполные данные.
|
Сообщ.
#16
,
|
|
|
Шифровку тоже надо бы подправить, т.к. код #13 предполагает, что длина зашифрованного текста всегда будет больше длины исходного. Лучше сделать так:
![]() ![]() X:=Length(login); if CryptEncrypt(key, 0, True, 0, nil, @X, X) then //при pbData=Nil просто в X возвращается требуемая длина begin if X > Length(login) then SetLength(login, X) else UniqueString(login); if not CryptEncrypt(key, 0, True, 0, Pointer(login), @X, X) then RaiseLastOSError else if X <> Length(login) then SetLength(login, X); end else RaiseLastOSError; |
Сообщ.
#17
,
|
|
|
CodeMonkey Подскажи запутался все равно ругается!
![]() ![]() login:=z_text; X := Length(login); if not CryptDecrypt(key, 0, True, 0, Pointer(login), @X) then RaiseLastOSError; Добавлено Спасибо! Расшифровывает, но только в конце слова не понятные символы доставляет!? |
Сообщ.
#18
,
|
|
|
Цитата mawa @ Расшифровывает, но только в конце слова не понятные символы доставляет!? При дешифровке длина текста уменьшается, добавь коррекцию длины: ![]() ![]() if not CryptDecrypt(key, 0, True, 0, Pointer(login), @X) then RaiseLastOSError else if X <> length(login) then SetLength(login,X); |
Сообщ.
#19
,
|
|
|
_________________________
Пример: Исходное : qweqweqweqwe27@ Расшифрованное : qweqweqweqwe27@ Добавлено Все работает !!!! leo Спасибо Большое !!!!!!!! respect! |
Сообщ.
#20
,
|
|
|
Цитата mawa @ login:=z_text; Учти, что при этом после CryptDecrypt строка z_text тоже изменится. Чтобы не изменялась нужно либо добавить UniqueString(login); либо сразу вместо присваивания сделать SetString(login,pChar(z_text),Length(z_text)); |
Сообщ.
#21
,
|
|
|
Вопрос, если пароль не правильный выдает плохие данные, тогда необходимо использовать связку : try - exsept ?
|
Сообщ.
#22
,
|
|
|
Да, если нужно вывести сообщение или еще что-то сделать.
Плюс закрытие всех хэндлов лучше делать в try\finally PS: странно, что у тебя FormatMessage не ту ошибку выдал, т.к. RaiseLastOSError использует тот же механизм |
Сообщ.
#23
,
|
|
|
leo
А зачем сохранять ![]() ![]() login:=z_text; Все итак нормально работает? |
Сообщ.
#24
,
|
|
|
Работать то работает, но при присваивании login:=z_text может копироваться только указатель на строку, в итоге login и z_text будут указывать на один и тот же текст и соотв-но изменение login в Decript приведет также и к изменению z_text. Если это не важно, то тогда вроде и незачем присвоение login:=z_text делать - можно сразу с z_text работать. Если же z_text не должна меняться, то нужно сделать UniqueString(login)
Добавлено Кстати вместо FormatMessage можно использовать SysErrorMessage из SysUtils ![]() ![]() e:=GetLastError; ShowMessage('Error '+IntToStr(e)+'. '+SysErrorMessage(e)); PS: Это если вместо генерации исключения просто выдавать сообщение об ошибке |
Сообщ.
#25
,
|
|
|
leo спасибо за помощь! Очень помоГ!
|
Сообщ.
#26
,
|
|
|
mawa, тебе тоже спс - за интересный вопрос
![]() |
Сообщ.
#27
,
|
|
|
Цитата leo @ PS: странно, что у тебя FormatMessage не ту ошибку выдал, т.к. RaiseLastOSError использует тот же механизм Я не удивлюсь, если авто вопроса напутал и с вызовом FormatMessage - поэтому FormatMessage возвращал не столько описание ошибки, сколько ошибку при вызове себя или что-то вроде этого. Похоже, автор вопроса больше действует методом научного тыка, слабо понимая, что же вообще он пишет. |
Сообщ.
#28
,
|
|
|
CodeMonkey
А где я напутал - вызов FormatMessage? Я в прошлом году делал лабу по алгоритму RC4, там все было ок, и литературы хватало. А вот с AES, сам не справился! Еще раз спасибо! |
Сообщ.
#29
,
|
|
|
А почему некоторые слова шифруется, но не расшифровываются (p.s. пароль ввожу верно)? Пишит - плохие данные!
Шифрование ![]() ![]() login:=text; // вход: login - данные для шифрования // Шаг 1: определяем, сколько надо байт для хранения зашифрованного текста X := Length(login); if not CryptEncrypt(key, 0, True, 0, Pointer(login), @X, Length(login)) then if GetLastError <> ERROR_MORE_DATA then RaiseLastOSError; // Шаг 2: выделили буфер (уже не 512, а ровно, сколько надо) Y := Length(login); SetLength(login, X); // Шаг 3: шифрование if not CryptEncrypt(key, 0, True, 0, Pointer(login), @Y, Length(login)) then RaiseLastOSError; SetLength(login, Y); {освобождаем контекст криптопровайдера} CryptReleaseContext(hProv, 0); Расшифрование ![]() ![]() login:=z_text; X := Length(login); if not CryptDecrypt(key, 0, True, 0, Pointer(login), @X) then RaiseLastOSError else if X <> length(login) then SetLength(login,X); {освобождаем контекст криптопровайдера} CryptReleaseContext(hProv, 0); |
Сообщ.
#30
,
|
|
|
Частный случай:
Проблема в том что когда шифруется слово получается длина 32 символа, затем это слово записуется в файлик. А при расшифровании считывается из файлика, но считывается 8 символов!! Что делать? Зашифр. ![]() ![]() //созд.файла AssignFile(f,Edit3.Text+'.txt'); Rewrite(f); CloseFile(f); //открытие на до запись AssignFile(f,Edit3.Text+'.txt'); Append(f); //шифрование login:=login+'|@@|'+pass; str:=Zawufrovat(password,login); writeln(f,str); CloseFile(f); расшифр ![]() ![]() //открытие файла t:=OpenDialog1.FileName; try AssignFile(f,t); reset(f); except; ShowMessage('Ошибка чтения файла !'); Exit; end; //читаем логин+пароль+конст readln(f,str); ShowMessage(IntToStr(length(str))+' '+str[length(str)]); password:=MaskEdit1.Text+p_const; //расшифрование try str:=Raswufrovat(password,str); except; ShowMessage('Не верный пароль 1!'); memo2.Lines.Add(password); Exit; end; |
Сообщ.
#31
,
|
|
|
Писать и читать файл как двоичный.
|
Сообщ.
#32
,
|
|
|
Цитата mawa @ А где я напутал - вызов FormatMessage? Видимо вызвал GetLastError повторно после вызова другой функции (например RaiseLastOSError или ShowMessage), хотя в #10 я тебе показывал как надо делать - вызвать один раз сразу после ошибки и сохранить значение в переменной для последующих манипуляций. Цитата mawa @ Проблема в том что когда шифруется слово получается длина 32 символа, затем это слово записуется в файлик. А при расшифровании считывается из файлика, но считывается 8 символов!! Что делать? Мда, чудак ты, брат ![]() С чего ты взял, что после шифрования твой текст останется вообще читабельным текстом, да еще и однострочным. Все стандартные алгоритмы шифрования - двоичные, а не символьные, поэтому в результате шифрования в строке могут оказаться служебные символы, например перевода строки $13, $10 и даже $0 - признак конца текста. Поэтому записывать\читать зашифрованные данные нужно в двоичный файл, а не в текстовый ![]() ![]() var f:file; begin ... AssignFile(f,FileName); //запись строки str в файл try rewrite(f,1); blockwrite(f,str[1],Length(str)); finally CloseFile(f); end; ... //чтение строки str из файла try reset(f,1); SetLength(str,FileSize(f)); //задаем размер строки = размеру файла blockread(f,str[1],Length(str)); //читаем весь файл finally CloseFile(f); end; Добавлено mawa И еще, несмотря на мое замечание #16, ты продолжаешь использовать вариант шифрования #29, предполагающий что длина зашифрованного текста всегда больше исходной. Ты уверен, что это так ? Я не уверен. Ясно, что AES блочный шифр, поэтому длина входного текста выравнивается вверх на 16 или 32 байта. Но если длина твоего login уже равна 16 или 32, то длина может и не измениться и в итоге алгоритм #29 зашифрует строку дважды. Правда я в #16 тоже накосячил с длинами, поэтому правильный вариант должен быть такой: ![]() ![]() X:=Length(login); if CryptEncrypt(key, 0, True, 0, nil, @X, X) then //при pbData=Nil просто в X возвращается требуемая длина begin Y:=Length(login); if X > Y then SetLength(login, X) else UniqueString(login); if not CryptEncrypt(key, 0, True, 0, Pointer(login), @Y, X) then RaiseLastOSError else if Y <> Length(login) then SetLength(login, Y); end else RaiseLastOSError; |