SecureRandom slow
-
Hi guys,
On SU 2014, I
require 'securerandom.rb'
, then useSecureRandom.uuid
.
But for whatever reason, the first uuid takes several seconds to be generated. After that, it's instantaneous.Any idea why?
-
IF you have the CHM Ruby dictionary (comes in the "doc" folder of a system Ruby install,) you can click on the methods, and a code box will appear. Often this code is in C, but in this case, they are pure Ruby.
SecureRandom::uuid
callsSecureRandom::random_bytes
# File lib/securerandom.rb, line 247 def self.uuid ary = self.random_bytes(16).unpack("NnnnnN") ary[2] = (ary[2] & 0x0fff) | 0x4000 ary[3] = (ary[3] & 0x3fff) | 0x8000 "%08x-%04x-%04x-%04x-%04x%08x" % ary end
SecureRandom::random_bytes
has several platform dependent conditional statements (I'll call them parts,) that execute one time setup code, then the else clause thereafter.
The part that executes on Windows, you see must load "Win32API.rb" which conditionally loads other libraries.
THEN, it sets up the Win API call object referenced by a instance var inSecureRandom
, that is then used thereafter.
The first part is used IFOpenSSL
is loaded, the second part used by Mac/UNIX-like OSes.)
The third partofSecureRandom::random_bytes
that is used by Windows:if !defined?(@has_win32) begin require 'Win32API' crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L') @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'VIP', 'L') hProvStr = " " * DL;;SIZEOF_VOIDP prov_rsa_full = 1 crypt_verifycontext = 0xF0000000 if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0 raise SystemCallError, "CryptAcquireContext failed; #{lastWin32ErrorMessage}" end type = DL;;SIZEOF_VOIDP == DL;;SIZEOF_LONG_LONG ? 'q' ; 'l' @hProv, = hProvStr.unpack(type) @has_win32 = true rescue LoadError @has_win32 = false end end if @has_win32 bytes = " ".force_encoding("ASCII-8BIT") * n if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0 raise SystemCallError, "CryptGenRandom failed; #{lastWin32ErrorMessage}" end return bytes end
So once
@has_win32
is defined, only the last small if statement is executed thereafter. -
Could it be initialization?
Click the source: http://ruby-doc.org/stdlib-2.0.0/libdoc/securerandom/rdoc/SecureRandom.html#method-c-random_bytesIf you run it on Windows, it runs the first time also the
if !defined?(@has_win32)
block, later only theif @has_win32
block. -
Thanks guys.
Ok so this is normal, my only option is to generate an uuid when the script loads and be done with it? (But it slows down SU's startup)
-
What do you need the UID for? Do you need this particular implementation?
-
I need it for keeping track of component definitions throughout sessions.
It would be easier if definitions had a persistent GUID (Why does the current one change when the definition changes? It's useless).In fact, all entities should have persistent GUIDs like groups and instances in 2014.
-
Why can't you save the defintion's guid into an attribute dictionary when it is first loaded (or created,) and thereafter let the API's change as it wants.
You simply use the original saved in the attribute.
-
@jiminy-billy-bob said:
I need it for keeping track of component definitions throughout sessions.
It would be easier if definitions had a persistent GUIDThen if I was you I would find a different GUID generator that doesn't have the overhead. This one seems to be aimed at security, not just a GUID. Often hash generator (which this looks like) make a point out of being slow to make cracking harder and more expensive.
You just need something random enough. Using the hash of the component name might be good enough for your use. Current definition name and time should give you a different hash per component name per object.id = "#{definition.name}#{Time.now}".hash
-
@dan rathbun said:
Why can't you save the defintion's guid into an attribute dictionary when it is first loaded (or created,) and thereafter let the API's change as it wants.
That can also work.
-
@tt_su said:
You just need something random enough. Using the hash of the component name might be good enough for your use. Current definition name and time should give you a different hash per component name per object.
Yeah I was looking at something like that. But Dan's solution is simpler and seems so obvious!
smack on the forehead
Advertisement