I was looking at https://hg.prosody.im/0.9/file/f755e0bdc60a/util/uuid.lua and wondering what happens after the server has just restarted. The sources of entropy it uses are:
* The current UNIX time (os.time())
* The CPU time used by Prosody (os.clock())
* tostring({})
The initial seed is determined by concatenating all of these and then calling SHA1, e.g.:
sha1("14486099260.02table: 0x1f85920")
* The exact second the server restarted is easy to observe, for example with XEP-0012. There may be some clock drift, but the number of values we need to check probably doesn't exceed 2^6.
* While testing the CPU time used by Prosody the first time util.uuid is included, I only observed values between 0.01 and 0.04 (with no extra decimal places), probably as it's one of the first things Prosody does. Lets say this has about 2^3 different values we need to try.
* This one is harder. To estimate this, here are the values used for the initial seed for 20 starts of Prosody (on 64-bits Linux, no luajit):
0x25d9500
0x22cd920
0x1cee920
0x1c28920
0x1c1f920
0x1991500
0x18d7500
0x1819920
0x17cc500
0x166c920
0x1394920
0x1385920
0x136a920
0x131c920
0x11d2500
0x11b0920
0xde4920
0xca0920
0xbed500
0x800500
If we assume that this is a random number from the range 0x0000000 - 0x4000000 which always ends in 0x20 or 0x00 then this can take about 2^19 different values.
So all of this together means we have about 28 bits of entropy for the initial seed. The very first UUID generated by Prosody (without extra plugins) is generated here:
https://hg.prosody.im/0.9/file/f755e0bdc60a/core/hostmanager.lua#l77
Which is used:
https://hg.prosody.im/0.9/file/f755e0bdc60a/plugins/mod_dialback.lua#l21
Obtaining the dialback secret of a server would allow an attacker to impersonate that server. An attacker with their own domain can carry out a normal dialback with the target server and use the dialback key that was used to brute-force that server's secret. After that they can impersonate the domain without having to spoof DNS. Estimating based on `openssl speed` on my laptop suggests 2^28 SHA1 calls would take about 72 seconds on my machine.
Zash
on
So, on *nix we can try to open /dev/urandom and a) seed the thing from that or b) just map random.bytes to urandom:read, possibly with some buffering.
Other platforms (read: Windows) are trickier. Using the OpenSSL random subsystem is one way.
One could also extract some random on shutdown and read it back on startup, which would limit this to the first startup (assuming util.random isn't terrible when seeded properly).
Changes
tagStatus-Accepted
tagMilestone-0.9
Zash
on
Fixed and released in 0.9.9. Thanks a lot for reporting!
I was looking at https://hg.prosody.im/0.9/file/f755e0bdc60a/util/uuid.lua and wondering what happens after the server has just restarted. The sources of entropy it uses are: * The current UNIX time (os.time()) * The CPU time used by Prosody (os.clock()) * tostring({}) The initial seed is determined by concatenating all of these and then calling SHA1, e.g.: sha1("14486099260.02table: 0x1f85920") * The exact second the server restarted is easy to observe, for example with XEP-0012. There may be some clock drift, but the number of values we need to check probably doesn't exceed 2^6. * While testing the CPU time used by Prosody the first time util.uuid is included, I only observed values between 0.01 and 0.04 (with no extra decimal places), probably as it's one of the first things Prosody does. Lets say this has about 2^3 different values we need to try. * This one is harder. To estimate this, here are the values used for the initial seed for 20 starts of Prosody (on 64-bits Linux, no luajit): 0x25d9500 0x22cd920 0x1cee920 0x1c28920 0x1c1f920 0x1991500 0x18d7500 0x1819920 0x17cc500 0x166c920 0x1394920 0x1385920 0x136a920 0x131c920 0x11d2500 0x11b0920 0xde4920 0xca0920 0xbed500 0x800500 If we assume that this is a random number from the range 0x0000000 - 0x4000000 which always ends in 0x20 or 0x00 then this can take about 2^19 different values. So all of this together means we have about 28 bits of entropy for the initial seed. The very first UUID generated by Prosody (without extra plugins) is generated here: https://hg.prosody.im/0.9/file/f755e0bdc60a/core/hostmanager.lua#l77 Which is used: https://hg.prosody.im/0.9/file/f755e0bdc60a/plugins/mod_dialback.lua#l21 Obtaining the dialback secret of a server would allow an attacker to impersonate that server. An attacker with their own domain can carry out a normal dialback with the target server and use the dialback key that was used to brute-force that server's secret. After that they can impersonate the domain without having to spoof DNS. Estimating based on `openssl speed` on my laptop suggests 2^28 SHA1 calls would take about 72 seconds on my machine.
So, on *nix we can try to open /dev/urandom and a) seed the thing from that or b) just map random.bytes to urandom:read, possibly with some buffering. Other platforms (read: Windows) are trickier. Using the OpenSSL random subsystem is one way. One could also extract some random on shutdown and read it back on startup, which would limit this to the first startup (assuming util.random isn't terrible when seeded properly).
ChangesFixed and released in 0.9.9. Thanks a lot for reporting!
Changes