I'm tryin to get the serial number of an Acer monitor looking into the windows registry.
I'm parsing the registry with this code in Python 3:
import winreg
from winreg import HKEY_LOCAL_MACHINE
subKey = "SYSTEM\CurrentControlSet\Enum\DISPLAY"
k = winreg.OpenKey(HKEY_LOCAL_MACHINE, subKey)
with winreg.OpenKey(HKEY_LOCAL_MACHINE, subKey) as k:
""""
Open the key 'HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY'
to get the info of all connected monitors
"""
i = 0
while True:
try:
with winreg.OpenKey(k, winreg.EnumKey(k, i)) as sk:
j = 0
while True:
try:
with winreg.OpenKey(sk, winreg.EnumKey(sk, j)) as ssk:
l = 0
while True:
try:
if (winreg.EnumKey(ssk, l) == "Control"):
try:
with winreg.OpenKey(ssk, "Device Parameters") as sssk:
strEDID = str(winreg.EnumValue(sssk, 0)[1])
try:
modelo = strEDID[strEDID.index("\\x00\\x00\\x00\\xfc") + len("\\x00\\x00\\x00\\xfc\\x00"):].split("\\")[0]
serie = strEDID[strEDID.index("\\x00\\x00\\x00\\xff") + len("\\x00\\x00\\x00\\xff\\x00"):].split("\\")[0]
except:
modelo = "Not Found"
serie = "Not Found"
print ("Modelo:", modelo)
print ("Serie:", serie, "\n")
fo = open("salTest.txt", "a")
fo.write(modelo + "\n")
fo.write(serie + "\n\n")
fo.close()
except OSError:
print ("Error")
break
else:
l += 1
except OSError:
break
j += 1
except OSError:
break
i += 1
except OSError:
break
As result i get an output in the cmd window like this:
Modelo: AL1716
Serie: L4802017396L
The problem is that the "Serie" isn't the real serial number (an Acer monitor serial number have 22 characters and looks like "ETL480201781700F4B396L")
There is a way to build the real serial number with the "Serie" and the SNID that identify the monitor too.
Here is an example of two Acer monitors:
S/N ORIGINAL: ETL48020178170 (0F4B)396L | # ETL480201781700F4B396L
------------------------------------------------------------------------------------
SNID: 8170 (0F4B)=03915 | 39 # 81700391539
S/N FROM SCRIPT: L4802017 396L | # L4802017396L
S/N ORIGINAL: ETL48020178170 (2C98)396L | # ETL480201781702C98396L
------------------------------------------------------------------------------------
SNID: 8170 (2C98)=11416 | 39 # 81701141639
S/N FROM SCRIPT: L4802017 396L | # L4802017396L
Anyone know how to get this info?
Thanks!
Acer provides the serial number after the 000000ff00 flag but the middle part of the serial number is hidden earlier in the EDID string.
So for example our EDID string looks like this:
00ffffffffffff0004723a03c4fe603324170103682f1e78ca9265a655559f280d5054bfef80714f8140818081c0810095000101010126399030621a274068b03600da281100001c000000fd00374c1e5011000a202020202020000000fc0042323236574c0a202020202020000000ff004c58565341303031383531300a007b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The serial number we want is this:
LXVSA0013360FEC48510
The first 8 characters of the serial number LXVSA001 is encoded as a hex string immediately after the '000000ff00' flag.
The last 4 characters of the serial number 8510 is encoded as a hex string after this first 8 characters.
000000ff00 4c|58|56|53|41|30|30|31|38|35|31|30|0a| <-- EDID (hex)
L X V S A O 0 1 8 5 1 0 (linefeed) <-- ascii
(^^^^ first part ^^^^^^)(last part)
Now the tricky middle part 3360fec4 is encoded as 4 strings earlier in the EDID.
33 is at position 30
60 is at position 28
fe is at position 26
c4 is at position 24
00ffffffffffff0004723a03
position 24 -> c4
position 26 -> fe
position 28 -> 60
position 30 -> 33
24170103682f1e78ca9265a655559f etc
When I say 'position' I mean take the EDID string as an array and index from 0.
They are hard to find because they are in reverse order.
In your example, the missing parts of your serial number 81700F4B should be located as 4 separate 2 character strings at locations 30, 28, 26, and 24 of your idid string. I can't test that because I don't have the full IDID.
Related
A script I am making scans a 5-character code and assigns it a number based on the contents of characters within the code. The code is a randomly-generated number/letter combination. For example 7D3B5 or HH42B where any position can be any one of (26 + 10) characters.
Now, the issue I am having is I would like to figure out the number from 1-(36^5) based on the code. For example:
00000 = 0
00001 = 1
00002 = 2
0000A = 10
0000B = 11
0000Z = 36
00010 = 37
00011 = 38
So on and so forth until the final possible code which is:
ZZZZZ = 60466176 (36^5)
What I need to work out is a formula to figure out, let's say G47DU in its number form, using the examples below.
Something like this?
function getCount(s){
if (!isNaN(s))
return Number(s);
return s.charCodeAt(0) - 55;
}
function f(str){
let result = 0;
for (let i=0; i<str.length; i++)
result += Math.pow(36, str.length - i - 1) * getCount(str[i]);
return result;
}
var strs = [
'00000',
'00001',
'00002',
'0000A',
'0000B',
'0000Z',
'00010',
'00011',
'ZZZZZ'
];
for (str of strs)
console.log(str, f(str));
You are trying to create a base 36 numeric system. Since there are 5 'digits' each digit being 0 to Z, the value can go from 0 to 36^5. (If we are comparing this with hexadecimal system, in hexadecimal each 'digit' goes from 0 to F). Now to convert this to decimal, you could try use the same method used to convert from hex or binary etc... system to the decimal system.
It will be something like d4 * (36 ^ 4) + d3 * (36 ^ 3) + d2 * (36 ^ 2) + d1 * (36 ^ 1) + d0 * (36 ^ 0)
Note: Here 36 is the total number of symbols.
d0, d1, d2, d3, d4 can range from 0 to 35 in decimal (Important: Not 0 to 36).
Also, you can extend this for any number of digits or symbols and you can implement operations like addition, subtraction etc in this system itself as well. (It will be fun to implement that. :) ) But it will be easier to convert it to decimal do the operations and convert it back though.
I want to take a number and convert it into lowercase a-z letters using VBScript.
For example:
1 converts to a
2 converts to b
27 converts to aa
28 converts to ab
and so on...
In particular I am having trouble converting numbers after 26 when converting to 2 letter cell names. (aa, ab, ac, etc.)
You should have a look at the Chr(n) function.
This would fit your needs from a to z:
wscript.echo Chr(number+96)
To represent multiple letters for numbers, (like excel would do it) you'll have to check your number for ranges and use the Mod operator for modulo.
EDIT:
There is a fast food Copy&Paste example on the web: How to convert Excel column numbers into alphabetical characters
Quoted example from microsoft:
For example: The column number is 30.
The column number is divided by 27: 30 / 27 = 1.1111, rounded down by the Int function to "1".
i = 1
Next Column number - (i * 26) = 30 -(1 * 26) = 30 - 26 = 4.
j = 4
Convert the values to alphabetical characters separately,
i = 1 = "A"
j = 4 = "D"
Combined together, they form the column designator "AD".
And its code:
Function ConvertToLetter(iCol As Integer) As String
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(iCol / 27)
iRemainder = iCol - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
Neither of the solutions above work for the full Excel range from A to XFD. The first example only works up to ZZ. The second example has boundry problems explained in the code comments below.
//
Function ColumnNumberToLetter(ColumnNumber As Integer) As String
' convert a column number to the Excel letter representation
Dim Div As Double
Dim iMostSignificant As Integer
Dim iLeastSignificant As Integer
Dim Base As Integer
Base = 26
' Column letters are base 26 starting at A=1 and ending at Z=26
' For base 26 math to work we need to adjust the input value to
' base 26 starting at 0
Div = (ColumnNumber - 1) / Base
iMostSignificant = Int(Div)
' The addition of 1 is needed to restore the 0 to 25 result value to
' align with A to Z
iLeastSignificant = 1 + (Div - iMostSignificant) * Base
' convert number to letter
ColumnNumberToLetter = Chr(64 + iLeastSignificant)
' if the input number is larger than the base then the conversion we
' just did is the least significant letter
' Call the function again with the remaining most significant letters
If ColumnNumber > Base Then
ColumnNumberToLetter = ColumnNumberToLetter(iMostSignificant) & ColumnNumberToLetter
End If
End Function
//
try this
function converts(n)
Dim i, c, m
i = n
c = ""
While i > 26
m = (i mod 26)
c = Chr(m+96) & c
i = (i - m) / 26
Wend
c = Chr(i+96) & c
converts = c
end function
WScript.Echo converts(1000)
Here's an example for better understanding of the question:
2.0.0-p353 :003 > puts Base64.decode64 content
Glad to see we managed to get your attention!
You'll find our message in the bottle. Choose one or more tools to open it;
drop me a mail if you're interested in working together.
$!'<
]!N3
!9<Z]NWl!Z]N
Q!]90!NW
<6<K$E
!'$*B0
K-!N3!
QW0o<!
f$Z!fW
<]]0K!<K!Q
l]9NK!`Z<K6!-?$K6N
!Z]NQ!f0!Z]<EE!`Z0!]90
H!$!EN]!Z]NQ!$--!]90!fNW
-!Z<EElf$EBZ!]N!]90!Z`'?
0*]!E<K0!N3!lN`W!W0ZQNKZ
0!3`EEZ]NQg1"LO^"OLFm"a[
1"#%d%[+X=R^"(a^"+OIR=F1
"IOX1"F%L7a%71["^O"=^"F=
C1":%j1"1FI"+O4411[+X=R^
"^mR1[+X=R^"[^OR"%.."^:1
"R:X%[1"RmX%I=.O4.OOI"^O
"^:1"[a(#1+^"F=L1"O4"mOa
X"X1[ROL[1"4aFF[^ORh2#&Y
2#JPe>M8#_P#&#\2Ye>,2#PY
>2M_2/#&Y,;>_2,_bY2#PM#&
#AeJ#)&\2/#\_&,D#b\>M8#\
PJ2#G>)Y&Y>2\#PS2M\PbY,2
/#)n#M2_5G>k#\_PS#&//#_;
2#hPY/#J>G&MP#_P#_;2#\b)
A2,_#G>M2#h;2M#\2M/>M8#b
\#&#J&>G#5bGG\_PS
CLUE #1
def decode_char(ch):
x = ord(ch) - 33
return None if (x % 3) else ' ' if x < 3 else chr(x / 3 + 64)
CLUE #2
function decodeChar(ch) {
var x = ch.charCodeAt(0) - 33
if (String.fromCharCode(x % 3 + 64) != 'A')
return null;
else if (x < 3)
return ' ';
else
return String.fromCharCode(x / 3 + 64)
}
CLUE #3
def decodeChar(c: Char): Option[Char] = c.toInt - 33 match {
case 2 => Some(' ')
case x if x % 3 > 1 => Some((x/3 + 64).toChar)
case _ => None
}
=> nil
The functions listed below the bottle do decode the bottle in a different ways. For example, JS code gives this:
"WE NOT ONLY USE JAVASCRIPT BUT COMPILE MORE LANGUAGES TO IT LIKE HAXE
ELM COFFEESCRIPT TYPESCRIPT STOP ADD THE PHRASE PYRAMIDOFDOOM TO THE
SUBJECT LINE OF YOUR RESPONSE FULL"
Other functions are giving different texts.
So the question here is: How to encrypt different texts in one "bottle" (encrypted text)?
Each character has a value encoded in it that denotes which algorithm is needed for decoding.
return None if (x % 3) -> Anything not a multiple of 3 (n%3 != 0) is ignored.
if (String.fromCharCode(x % 3 + 64) != 'A') return null; -> All characters not (n*3)+1, i.e. n%3 != 1, are ignored
if x % 3 > 1 => ... -> only characters with (n%3) > 1, i.e. n%3 = 2, are decoded, others are ignored.
EDIT:
The encryption can be inferred as
c_output = ((c_input-64) * 3) + msg_no
where msg_no is the number of the message (less than 3) the input character belongs to.
If you take a bigger number than 3 you can encode more different messages into the same stream. However, it is important that c_output is still in the valid range for the datatype, e.g. a single ASCII character or byte. With 3 different message streams, encoding a ยต (code 181 in ASCII) is not possible: (181-64) * 3 > 255. Equally, 9 (code 57 in ASCII) cannot be encoded because (57-64)*3 < 0.
I had a input which is a result from text comparison. It is in a very simple format. It has 3 columns, position, original texts and new texts.
But some of the records looks like this
4 ATCG ATCGC
10 1234 123
How to write the short script to normalize it to
7 G GC
12 34 3
probably, the whole original texts and the whole new text is like below respectively
ACCATCGGA1234
ACCATCGCGA123
"Normalize" means "trying to move the position in the first column to the position that changes gonna occur", or "we would remove the common prefix ATG, add its length 3 to the first field; similarly on line 2 the prefix we remove is length 2"
This script
awk '
BEGIN {OFS = "\t"}
function common_prefix_length(str1, str2, max_len, idx) {
idx = 1
if (length(str1) < length(str2))
max_len = length(str1)
else
max_len = length(str2)
while (substr(str1, idx, 1) == substr(str2, idx, 1) && idx < max_len)
idx++
return idx - 1
}
{
len = common_prefix_length($2, $3)
print $1 + len, substr($2, len + 1), substr($3, len + 1)
}
' << END
4 ATCG ATCGC
10 1234 123
END
outputs
7 G GC
12 34 3
I need to generate repeatable pseudo random numbers based on a set of coordinates, so that with a given seed, I will always generate the same value for a specific coordinate.
I figured I'd use something like this for the seed:
/* 64bit seed value*/
struct seed_cord {
uint16 seed;
uint16 coord_x_int;
uint16 coord_y_int;
uint8 coord_x_frac;
uint8 coord_y_frac;
}
Where coord_x_int is the integer part of the coordinate, and the fraction part is given by coord_x_frac / 0xFF. seed is a randomly pre-determined value.
But I must admit, trying to understand all the intricacies of PRNGs is a little overwhelming. What would be a good generator for what I'm attempting?
I tested out Java's PRNG using using this scheme in a quick groovy script, with the following result:
Obviously, this is hardly decent randomness.
The script I used was:
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
short shortSeed = new Random().next(16) as short
def image = new BufferedImage(512, 512, BufferedImage.TYPE_BYTE_GRAY)
def raster = image.getRaster()
//x
(0..1).each{ x ->
(0..255).each{ xFrac ->
//y
(0..1).each{ y ->
(0..255).each{ yFrac ->
long seed = (shortSeed as long) << 48 |
(x as long) << 32 |
(y as long) << 16 |
(xFrac as long) << 8 |
(yFrac as long)
def value = new Random(seed).next(8)
raster.setSample( (x? xFrac+256 : xFrac), (y? yFrac+256 : yFrac), 0 , value)
}}}}
ImageIO.write(image, "PNG", new File("randomCoord.png"))
If you're really only looking at 512x512, then that's uh... 218 pixels you're interested in.
There's plenty of space for that kind of population with good ole MD5 (128 bit output).
You can just take the lowest 32 bits for an integer if that's the kind of output you need. Really, any sort of hashing algorithm that has an output space at least as large as an int will do.
Now, you can do all sorts of fun stuff if you're paranoid. Start with a hash of your coordinates, then feed the result into a secure random number generator (java.security.SecureRandom). Then hash it 1000 times with a salt that's your birthday concatenated (x+y) times.
Joking aside, random number generators don't necessarily have wildly varying results based on small variations of the seed. They're designed to have a really, super duper long chain of generated numbers before they start repeating, while having those chains pretty evenly distributed among the number space.
On the other hand, the SecureRandom is designed to have the additional feature of being chaotic in regard to the seed.
Most languages have a PRNG package (or two) that lets you initialize the generator with a specific seed. PRNGs can also often be found as part of a larger cryptographic package; they tend to be a bit stronger than those found in general-purpose libraries.
I would take a program like this one I have created and then modify it to pick coordinates:
REM $DYNAMIC
COMMON SHARED n%, rbuf%, sz%, sw%, p1$
DECLARE SUB initialize ()
DECLARE SUB filbuf ()
DECLARE SUB setup ()
DECLARE FUNCTION Drnd# ()
DECLARE SUB core ()
DECLARE SUB modify ()
DIM SHARED pad1(340) AS STRING * 1
DIM SHARED trnsltr(66) AS STRING * 1 ' translates a 0-67 value into a pad character
DIM SHARED trnslt(255) AS INTEGER 'translates a pad value to 0-67 value -1 if error
DIM SHARED moders(26) AS INTEGER 'modding function prim number array
DIM SHARED moders2(26) AS INTEGER 'modding function prim number array
DIM SHARED ranbuf(1 TO 42) AS DOUBLE 'random number buffer if this is full and rbuf %>0
REM then this buffer is used to get new random values
REM rbuf% holds the index of the next random number to be used
REM subroutine setup loads the prime number table
REM from the data statements to be used
REM as modifiers in two different ways (or more)
REM subroutine initialize primes the pad array with initial values
REM transfering the values from a string into an array then
REM makes the first initial scrambling of this array
REM initializing pad user input phase:
CLS
INPUT "full name of file to be encrypted"; nam1$
INPUT "full name of output file"; nam2$
INPUT "enter password"; p2$
rbuf% = 0
n% = 0: sw% = 0
p3$ = STRING$(341, "Y")
p1$ = "Tfwd+-$wiHEbeMN<wjUHEgwBEGwyIEGWYrg3uehrnnqbwurt+>Hdgefrywre"
p1$ = p2$ + p1$ + p3$
PRINT "hit any key to continue any time after a display and after the graphic display"
p1$ = LEFT$(p1$, 341)
sz% = LEN(p1$)
CALL setup
CALL initialize
CLS
ibfr$ = STRING$(512, 32)
postn& = 1
OPEN nam1$ FOR BINARY AS #1
OPEN nam2$ FOR BINARY AS #2
g& = LOF(1)
max& = g&
sbtrct% = 512
WHILE g& > 0
LOCATE 1, 1
PRINT INT(1000 * ((max& - g&) / max&)) / 10; "% done";
IF g& < 512 THEN
ibfr$ = STRING$(g&, 32)
sbtrct% = g&
END IF
GET #1, postn&, ibfr$
FOR ste% = 1 TO LEN(ibfr$)
geh% = INT(Drnd# * 256)
MID$(ibfr$, ste%, 1) = CHR$(geh% XOR ASC(MID$(ibfr$, ste%, 1)))
NEXT ste%
PUT #2, postn&, ibfr$
postn& = postn& + sbtrct%
g& = g& - sbtrct%
WEND
CLOSE #2
CLOSE #1
PRINT "hit any key to exit"
i$ = ""
WHILE i$ = "": i$ = INKEY$: WEND
SYSTEM
END
DATA 3,5,7,9,11,13,17,19
DATA 23,29,33,37,43,47
DATA 53,59,67,71,73,79,83
DATA 89,91,97,101,107,109
DATA 43,45,60,62,36
REM $STATIC
SUB core
REM shuffling algorythinm
FOR a% = 0 TO 339
m% = (a% + 340) MOD 341: bez% = trnslt(ASC(pad1(340)))
IF n% MOD 3 = 0 THEN pad1(340) = trnsltr((2 * trnslt(ASC(pad1(a%))) + 67 - trnslt(ASC(pad1(m%)))) MOD 67)
IF n% MOD 3 = 1 THEN pad1(340) = trnsltr((2 * (67 - trnslt(ASC(pad1(a%)))) + 67 - trnslt(ASC(pad1(m%)))) MOD 67)
IF n% MOD 3 = 2 THEN pad1(340) = trnsltr(((2 * trnslt(ASC(pad1(a%))) + 67 - trnslt(ASC(pad1(m%)))) + moders(n% MOD 27)) MOD 67)
pad1(a% + 1) = pad1(m%): n% = (n% + 1) MOD 32767
pad1(a%) = trnsltr((bez% + trnslt(ASC(pad1(m%)))) MOD 67)
NEXT a%
sw% = (sw% + 1) MOD 32767
END SUB
FUNCTION Drnd#
IF rbuf% = 0 THEN
CALL core
CALL filbuf
IF sw% = 32767 THEN CALL modify
END IF
IF rbuf% > 0 THEN yut# = ranbuf(rbuf%)
rbuf% = rbuf% - 1
Drnd# = yut#
END FUNCTION
SUB filbuf
q% = 42: temp# = 0
WHILE q% > 0
FOR p% = 1 TO 42
k% = (p% - 1) * 8
FOR e% = k% TO k% + 7
temp# = temp# * 67: hug# = ABS(trnslt(ASC(pad1(e%)))): temp# = temp# + hug#
NEXT e%
IF temp# / (67 ^ 8) >= 0 AND q% < 43 THEN
ranbuf(q%) = temp# / (67 ^ 8): q% = q% - 1
END IF
temp# = 0
NEXT p%
WEND
rbuf% = 42
END SUB
SUB initialize
FOR a% = 0 TO 340
pad1(a%) = MID$(p1$, a% + 1, 1)
NEXT a%
FOR a% = 0 TO 340
LOCATE 1, 1
IF a% MOD 26 = 0 THEN PRINT INT((340 - a%) / 26)
sum% = 0
FOR b% = 0 TO 340
qn% = INT(Drnd# * 81)
op% = INT(qn% / 3)
qn% = qn% MOD 3
IF qn% = 0 THEN sum% = sum% + trnslt(ASC(pad1(b%)))
IF qn% = 1 THEN sum% = sum% + (67 + 66 - trnslt(ASC(pad1(b%)))) MOD 67
IF qn% = 2 THEN sum% = sum% + trnslt(ASC(pad1(b%))) + moders(op%)
NEXT b%
pad1(a%) = trnsltr(sum% MOD 67)
NEXT a%
n% = n% + 1
END SUB
SUB modify
REM modifier shuffling routine
q% = 26
temp# = 0
WHILE q% > -1
FOR p% = 1 TO 27
k% = (p% - 1) * 4 + 3
FOR e% = k% TO k% + 3
temp# = temp# * 67
hug# = ABS(trnslt(ASC(pad1(e%))))
temp# = temp# + hug#
NEXT e%
IF (temp# / (67 ^ 4)) >= 0 AND q% > -1 THEN
SWAP moders(q%), moders(INT(27 * (temp# / (67 ^ 4))))
q% = q% - 1
END IF
temp# = 0
NEXT p%
WEND
END SUB
SUB setup
FOR a% = 0 TO 26
READ moders(a%)
moders2(a%) = moders(a%)
NEXT a%
REM setting up tables and modder functions
FOR a% = 0 TO 25
trnsltr(a%) = CHR$(a% + 97)
trnsltr(a% + 26) = CHR$(a% + 65)
NEXT a%
FOR a% = 52 TO 61
trnsltr(a%) = CHR$(a% - 4)
NEXT a%
FOR a% = 62 TO 66
READ b%
trnsltr(a%) = CHR$(b%)
NEXT a%
FOR a% = 0 TO 255
trnslt(a%) = -1
NEXT a%
FOR a% = 0 TO 66
trnslt(ASC(trnsltr(a%))) = a%
NEXT a%
RESTORE
END SUB
the call to drand# gives you random numbers from 0 to 1 simply multiply that by your needed range for each vector needed p2$ is the password that is passed to the password handler which combines it with some other random characters and then caps the size to a certain limit p1$ is where the final modified password is contained
drand# itself calls another sub which is actually a clone of itself with some shuffling of
sorts that works to ensure that the numbers being produced are truly random there is also a table of values that are added in to the values being added all this in total makes the RNG many many more times random with than without.
this RNG has a very high sensitivity to slight differences in password initially set you must however make an intial call to setup and initialize to "bootstrap" the random number generator this RNG will produce Truly random numbers that will pass all tests of randomness
more random even then shuffling a deck of cards by hand , more random than rolling a dice..
hope this helps using the same password will result in the same sequnece of vectors
This program would have to be modified a bit though to pick random vectors rather than
it's current use as a secure encryption random number generator...
You can use encryption for this task, for example AES. Use your seed as the password, struct with coordinates as the data block and encrypt it. The encrypted block will be your random number (you can actually use any part of it). This approach is used in the Fortuna PRNG. The same approach can be used for disk encryption where random access of data is needed (see Random access encryption with AES In Counter mode using Fortuna PRNG:)