Войти

Показать полную графическую версию : [решено] Вернуть рандомную фразу


Страниц : 1 [2]

Creat0R
11-07-2009, 08:53
Есть способ гораздо проще: »
Это то что я делаю в своём примере. Но по всей видимости, простота не нужна :)

tweakos
11-07-2009, 11:22
Это то что я делаю в своём примере. Но по всей видимости, простота не нужна »
я всего лишь показал способ без использования функций....и не утверждаю что он лучше...но он действительно немного проще....

amel27
11-07-2009, 13:20
по всей видимости, простота не нужна »угу, такие случаи надо оговаривать заранее...

На самом деле, MT19937, используемый в AutoIT - алгоритм ПСЕВДОслучайных чисел (http://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80_%D0%BF%D1%81%D0%B5%D0%B2%D0%B4%D0%BE%D1%81%D0 %BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB), где ВСЯ последовательность полностью задаётся ОДНИМ входным 32-х битным числом - чем больше у нас "в кармане" сгенерированных чисел из одной последовательности, тем ближе мы к оценке исходного "ключа". Сам "ключ" обычно генерится на основе показаний внутренних часов. Отсюда понятно, что для серьезных задач штатный генератор не подходит - только для тестирования своего кода... кстати, по указанному линку есть полезная сравнительная табличка разных алгоритмов.

P.S. Т.о., максимальное "пространство атаки" составляет у нас всего 32 бита и не зависит от длины пароля!

P.P.S. Генератор случайных чисел в Windows оказался не случайным (http://www.xakep.ru/post/41111/default.asp) :)

Creat0R
11-07-2009, 19:47
amel27, Кстати, это (не надёжность генерации СЧ) и видно с простого примера, где два раза подряд возвращается одно и то же, якобы случайное число, и причём с разных процессов:


Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test 1'', ''Random: '' & Random(1, 5))"')
Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test 2'', ''Random: '' & Random(1, 5))"')

WinWait('Random Test 2')

WinMove('Random Test 1', 'Random: ', (@DesktopWidth/2)-200, (@DesktopHeight/2)-40)
WinMove('Random Test 2', 'Random: ', (@DesktopWidth/2)+100, (@DesktopHeight/2)-40)

amel27
12-07-2009, 08:13
Creat0R, я тоже это заметил при отладке UDF: для того, чтобы каждый процесс имел свою уникальную "случайную последовательность", пауза между запусками должна быть больше определенного интервала (~500мс)

Мне вообще не нравится, как реализован Rundom() в AutoIT. ИМХО программист сам должен выполнять инициализацию случайной последовательности, как это делается в других языках... Иначе вся работа Rundom() оказывается жестко привязана к времени запуска скрипта - глупость несусветная, вся фишка "воспроизводимости" коту под хвост... Кроме того, создается ложный миф "случайности" полученных чисел.

amel27
12-07-2009, 18:23
собственно, метод, рекомендуемый Microsoft (тот самый CryptoAPI):
ConsoleWrite(_Crypto_GetRandomString(12, 7) &@CRLF)

; =============================================================================
; _Crypto_GetRandomString($iLen[, $iFlag])
; -----------------------------------------------------------------------------
; Получение случайной символьной строки заданной длины
;
; $iLen : длина получаемой строки
; $iFlag : какие символы используются при генерации строки
; : 1 - цифры
; : 2 - большие английские буквы
; : 4 - малые английские буквы
; : 8 - основные спецсимволы
; : 16 - дополнительные спецсимволы
; : 32 - русские буквы
;
; При успехе : возвращает бинарную строку
;
; При неудаче : пустая строка:
; : @error, @extended - код ошибки _Crypto_GetRandomBinary()
;
; : AutoIT v3.3.0.0
; =============================================================================
Func _Crypto_GetRandomString($iLen, $iFlag = 15)
Local $iMid, $sABC = "", $sOut = ""
If BitAND($iFlag,1) Then $sABC &= "0123456789"
If BitAND($iFlag,2) Then $sABC &= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If BitAND($iFlag,4) Then $sABC &= "abcdefghijklmnopqrstuvwxyz"
If BitAND($iFlag,8) Then $sABC &= "~!@#$%^&*()_"
If BitAND($iFlag,16) Then $sABC &= '`+-=",.<>/?\|[]{};:'&"'"
If BitAND($iFlag,32) Then $sABC &= 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя'
Local $iABC = StringLen($sABC)
Local $bPWD = _Crypto_GetRandomBinary($iLen)
If @error Then Return SetError(@error, @extended, $sOut) ; Ошибка _Crypto_GetBinary

For $i=1 To BinaryLen($bPWD)
$iMid = Int(BinaryMid($bPWD,$i,1))*$iABC/0x100+1
$sOut &= StringMid($sABC, $iMid, 1)
Next
Return $sOut
EndFunc ; ==> _Crypto_GetRandomString

; =============================================================================
; _Crypto_GetRandomBinary($iLen)
; -----------------------------------------------------------------------------
; Получение случайной строки байтов заданной длины
;
; $iLen : количество байтов в бинарной строке
;
; При успехе : возвращает бинарную строку
;
; При неудаче : возвращаемое значение не является бинарной строкой:
; : @error=1, @extended=1 - ошибка открытия advapi32.dll
; : @error=1, @extended=2 - ошибка открытия kernel32.dll
; : @error=2 - RunTime ошибка API, @extended - код ошибки
;
; : AutoIT v3.3.0.0
; =============================================================================
Func _Crypto_GetRandomBinary($iLen)
Local $phProv = DllStructCreate("ulong_ptr"), $aRet
Local $pbBuffer = DLLStructCreate("byte[" & $iLen & "]")
; Открытие DLL
Local $hAdvApi = DllOpen("advapi32.dll"), $hKernel = DllOpen("kernel32.dll")
If $hAdvApi=-1 Then Return SetError(1, 1, DllClose($hKernel)) ; Ошибка открытия advapi32.dll
If $hKernel=-1 Then Return SetError(1, 2, DllClose($hAdvApi)) ; Ошибка открытия kernel32.dll
; Создание описателя криптохранилища
$aRet = DllCall($hAdvApi, "int", "CryptAcquireContext", _
"ptr", DllStructGetPtr($phProv), "ptr", 0, "ptr", 0, "dword", 1, "dword", 0xF0000000)
If $aRet[0]=0 Then $aRet = DllCall($hKernel, "int", "GetLastError")
If UBound($aRet)=1 And $aRet[0]=0x80090016 Then
$aRet = DllCall($hAdvApi, "int", "CryptAcquireContext", _
"ptr", DllStructGetPtr($phProv), "ptr", 0, "ptr", 0, "dword", 1, "dword", 0xF0000008)
If $aRet[0]=0 Then $aRet = DllCall($hKernel, "int", "GetLastError")
EndIf
If UBound($aRet)>1 Then
; Генерация случайной последовательности байтов
$aRet = DllCall($hAdvApi, "int", "CryptGenRandom", _
"ptr", DllStructGetData($phProv, 1), "dword", $iLen, "ptr", DllStructGetPtr($pbBuffer))
If $aRet[0]=0 Then $aRet = DllCall($hKernel, "int", "GetLastError")
; Закрытие описателя криптохранилища
DllCall($hAdvApi, "long", "CryptReleaseContext", _
"ulong_ptr", DllStructGetData($phProv, 1), "dword", 0)
EndIf
DllClose($hKernel)
DllClose($hAdvApi)

If UBound($aRet)=1 Then Return SetError(2, $aRet[0], 0) ; Ошибка API RunTime
Return DllStructGetData($pbBuffer, 1) ; Возврат строки
EndFunc ; ==> _Crypto_GetRandomBinary

Creat0R
12-07-2009, 22:58
amel27, Что-то у меня функция возвращает ошибку (@error = 1, @extended = 1)...

amel27
13-07-2009, 09:42
Creat0R, у меня вроде нормально, попробуй измененный вариант... а вообще, в таких случаях нужно проверить UDF для бинарной строки - там возвращается расширенный код ошибки GetLastError()

ADD: т.к. первая UDF лишь враппер - сделал возврат ошибок одинаковым

Creat0R
13-07-2009, 15:36
попробуй измененный вариант »
@error = 2
@extended = 87

:dont-know

Мда, это под AutoIt 3.2.8.1 :blush2: - Под 3.3.0.0 нормально работает. Интересно, а под 3.2.8.1 можно функцию подстроить? У меня просто есть ещё пару старых проектов на этой версии, из за этого у меня и была включена эта версия, как раз сейчас работаю над одним из них (проектов).

Creat0R
13-07-2009, 15:55
Оно работает в обеих версиях если заменить "ulong_ptr" на "long" (или на "ptr"). Но насколько оно будет надёжно?

P.S
Кстати, а таким же методом, можно сделать UDF-аналог на Random(), т.е чтобы более надёжно возвращать случайное число?

amel27
13-07-2009, 19:08
работает в обеих версиях если заменить "ulong_ptr" на "long" (или на "ptr"). Но насколько оно будет надёжно? »AFAIK "ulong_ptr" отличается от "ulong" только автоматичеким определением разрядности - для переносимости кода между 32 и 64-битным AutoIT... мне почему-то кажется, что одного этого маловато будет, на 64-бит пока не тестил... :unsure:

таким же методом, можно сделать UDF-аналог на Random(), т.е чтобы более надёжно возвращать случайное число? »да можно конечно... но ИМХО в такой замене нет нужды: назначение штатного генератора обычно совсем другое - моделирование, тестирование и отладка - в этом случае его предсказуемость и воспроизводимость как нельзя кстати, при "сбое" всегда можно "перезапустить" случайную последовательность и отловить баг... Потому я и говорю о странном позиционировании Random() в AutoIT, надо-то всего ничего - добавить один необязательный параметр для инициализации генератора.

математик из меня никудышный... вроде похоже на правду:
For $i=1 To 1000
ConsoleWrite(_Random() &@CRLF)
Next

Func _Random($iMin=0, $iMax=1, $iFlag=0)
Local $bBIN, $iOut
Local $tMAX = DllStructCreate("uint")
Local $tBIN = DllStructCreate("byte[4];byte[4]")
Local $tRND = DllStructCreate("uint64", DllStructGetPtr($tBIN))
Do
$bBIN = _Crypto_GetRandomBinary(4)
Until ($bBIN<>Binary(0)) And ($bBIN<>Binary(-1))

DllStructSetData($tBIN, 1, $bBIN)
DllStructSetData($tMAX, 1, 0xFFFFFFFF)

If $iFlag=0 Then $iOut = DllStructGetData($tRND,1)*($iMax-$iMin)/DllStructGetData($tMAX,1)
If $iFlag Then $iOut = Int(DllStructGetData($tRND,1)*($iMax-$iMin+1)/DllStructGetData($tMAX,1))

Return $iOut + $iMin
EndFunc

Creat0R
13-07-2009, 23:22
в этом случае его предсказуемость и воспроизводимость как нельзя кстати, при "сбое" всегда можно "перезапустить" случайную последовательность и отловить баг... »
Random() можно использовать в качестве отладчика багов? это для меня что-то новое, можно подробнее плиз?

надо-то всего ничего - добавить один необязательный параметр для инициализации генератора. »
Может на этот счёть запостить Feature Request?

математик из меня никудышный... вроде похоже на правду »
Ага, мне бы таким никудышным математиком стать :cool:

Спасибо за _Random().

amel27
14-07-2009, 08:25
можно подробнее плиз? » не в качестве отладчика, а при отладке... навскидку два варианта:

- на время тестирования кода, использующего криптоалгоритмы, можно заменить случайный генератор на псевдослучайный, т.к. последний работает во много раз быстрее;

- проверка устойчивости форм ввода (Web, GUI) к всевозможным "неправильным" данным - когда нет возможности перебрать ВСЕ возможные комбинации, можно сгенерировать последовательность случайных ... т.е. проверка способности входных регулярных выражений фильтовать "спам";

- вообще, во всех случаях, где НЕ нужна криптостойкость, но нужны скорость/воспроизводимость

Может на этот счёть запостить Feature Request? »подумаю... надо же еще предложить как оформить... хотя, если ты проникся необходимостью, можешь и сам отправить (меня английский грузит)... для сравнения: в VB случайная последовательность инициализируется Randomize() (http://msdn.microsoft.com/en-us/library/8zedbtdt(VS.80,printer).aspx), а само число возвращается ф-цией RND() (http://msdn.microsoft.com/en-us/library/f7s023d2(VS.80,printer).aspx)

Спасибо за _Random() »
спасибо FlatX007 за хороший вопрос ;)




© OSzone.net 2001-2012