Показать полную графическую версию : [решено] Вернуть рандомную фразу
Есть способ гораздо проще: »
Это то что я делаю в своём примере. Но по всей видимости, простота не нужна :)
Это то что я делаю в своём примере. Но по всей видимости, простота не нужна »
я всего лишь показал способ без использования функций....и не утверждаю что он лучше...но он действительно немного проще....
по всей видимости, простота не нужна »угу, такие случаи надо оговаривать заранее...
На самом деле, 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) :)
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)
Creat0R, я тоже это заметил при отладке UDF: для того, чтобы каждый процесс имел свою уникальную "случайную последовательность", пауза между запусками должна быть больше определенного интервала (~500мс)
Мне вообще не нравится, как реализован Rundom() в AutoIT. ИМХО программист сам должен выполнять инициализацию случайной последовательности, как это делается в других языках... Иначе вся работа Rundom() оказывается жестко привязана к времени запуска скрипта - глупость несусветная, вся фишка "воспроизводимости" коту под хвост... Кроме того, создается ложный миф "случайности" полученных чисел.
собственно, метод, рекомендуемый 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
amel27, Что-то у меня функция возвращает ошибку (@error = 1, @extended = 1)...
Creat0R, у меня вроде нормально, попробуй измененный вариант... а вообще, в таких случаях нужно проверить UDF для бинарной строки - там возвращается расширенный код ошибки GetLastError()
ADD: т.к. первая UDF лишь враппер - сделал возврат ошибок одинаковым
попробуй измененный вариант »
@error = 2
@extended = 87
:dont-know
Мда, это под AutoIt 3.2.8.1 :blush2: - Под 3.3.0.0 нормально работает. Интересно, а под 3.2.8.1 можно функцию подстроить? У меня просто есть ещё пару старых проектов на этой версии, из за этого у меня и была включена эта версия, как раз сейчас работаю над одним из них (проектов).
Оно работает в обеих версиях если заменить "ulong_ptr" на "long" (или на "ptr"). Но насколько оно будет надёжно?
P.S
Кстати, а таким же методом, можно сделать UDF-аналог на Random(), т.е чтобы более надёжно возвращать случайное число?
работает в обеих версиях если заменить "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
в этом случае его предсказуемость и воспроизводимость как нельзя кстати, при "сбое" всегда можно "перезапустить" случайную последовательность и отловить баг... »
Random() можно использовать в качестве отладчика багов? это для меня что-то новое, можно подробнее плиз?
надо-то всего ничего - добавить один необязательный параметр для инициализации генератора. »
Может на этот счёть запостить Feature Request?
математик из меня никудышный... вроде похоже на правду »
Ага, мне бы таким никудышным математиком стать :cool:
Спасибо за _Random().
можно подробнее плиз? » не в качестве отладчика, а при отладке... навскидку два варианта:
- на время тестирования кода, использующего криптоалгоритмы, можно заменить случайный генератор на псевдослучайный, т.к. последний работает во много раз быстрее;
- проверка устойчивости форм ввода (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
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.