Implementation Pitfalls in Cryptography: Random Number Generation - Prof. Alexandra Boldyr, Study notes of Cryptography and System Security

The importance of using cryptographic protocols with proofs of security and the challenges of implementing random number generators. It provides examples of flawed approaches using the c random number generator and the netscape browser's random number generation method. Students can learn about the importance of secure random number generation and the potential risks of using flawed methods.

Typology: Study notes

Pre 2010

Uploaded on 08/05/2009

koofers-user-vo9
koofers-user-vo9 🇺🇸

10 documents

1 / 3

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Implementation pitfalls
We learned about various cryptographic primitives and the
provable security approach, saw many secure constructions.
You are almost ready to employ this knowledge in practice.
Let us review some common mistakes one needs to be aware
of and avoid when implementing cryptographic protocols.
1
Always remember to
Use widely accepted and believed to be secure building blocks
(e.g. AES).
Use provably secure (under reasonable assumptions)
constructions (e.g. $CBC).
Do not assume that the schemes provide security properties
other than what is proven about them (e.g. encryption does
not provide authenticity).
Realize that the use of a provably secure scheme does not
guarantee that the entire system will be secure.
Make sure that you implement exactly the scheme that was
proven secure.
2
Not using the right primitives
ATM-based passive optical networks commonly use a block
cipher called CHURN. It’s key size is 8 bits and it’s block size
is 4 bits!
The use of the ECB mode and the Plain RSA encryption is still
very common.
Using the constructs without security proofs
3
One can prove that for every A making q queries there exists B s.t.
Is CTRS$ secure?
Not considering the security bounds
Let E:{0,1}k!{0,1}n!{0,1}n be a block cipher.
R"{0,1}L
EK
C[1]
EK
C[2]
EK
C[m]
󲰟 󲰟 󲰟
R||<1> R||<2> R||<m>
M[2] M[m]
M[1]
R
Consider the encryption algorithm of a scheme CTRS$[L]
Kohno 3
8.2 Using a construct without proofs of security
There have been numerous cryptographic protocols, like encryption schemes and MACs, that did
not come with proofs of security. That’s not surprising since people did not start to prove the
security of block cipher-based encryption schemes and MACs until the 1990s. What is unfortunate
is that, without proofs of security, it is impossible to know whether a construction is actually secure
or not. In fact, in the exercises you have already been asked to find attacks against constructions
that do not come with proofs of security, even if they might appear secure at first sight.
Nowadays, many more people understand that it is important to use cryptographic protocols
that come with proofs of security. Still, it is not uncommon to find homebrew security software
using the ECB encryption mode, or something akin to CBCC. (We’ll get back to some examples
later.)
Hopefully, the discussions in Chapters 4 through 7 strongly motivate the fact that, whenever
possible, software applications should use constructions that are provably secure under reasonable
assumptions.
8.3 Not considering the security bounds
Another common implementation pitfall is to not fully understand the security bounds in the proofs.
We saw a little bit of this when we discussed CBC$ with FEAL in Section 8.1 of this chapter. But
now let’s consider the case where we actually believe that the underlying cryptographic primitive
is secure.
Let us define the encryption scheme CTRS$[L] = (K,E,D) with a block cipher E:{0,1}k×
{0,1}n{0,1}n. Here Lis an integer between 1 and n1, and is a parameter of our construction.
The key generation algorithm returns a randomly selected value from {0,1}k. The encryption algo-
rithm is shown below, and the decryption algorithm is defined in the natural way. This construction
is very similar to CTR$ from Chapter 5.
algorithm EK(M)
m %|M|/n&
If m2nlthen return
R$
{0,1}L
Pad EK(R)*1+))EK(R)*2+))·· · EK(R)*m+)
Pad the first |M|bits of Pad
C"MPad
CR)C"
return C
Here *x+denotes the nL-bit encoding of the integer x{0,...,2nL1}.
We can prove the following result about the above construction.
Theorem 8.3.1 Let E:{0,1}k×{0,1}n{0,1}nbe a family of functions, let L{1,...,n1}
be an integer, and let CTRS$[L] = (K,E,D)be the corresponding CTRS$[L]symmetric encryp-
tion scheme as described above. Let Abe an adversary (for attacking the IND-CPA security of
CTRS$[L]) that runs in time at most tand asks at most qqueries, these totaling at most σn-bit
blocks. Then there exists an adversary B(attacking the PRF security of E) such that
Advind-cpa
CTRS$[L](A)Advprf
E(B) + q2
2L+1 .(8.1)
4
pf3

Partial preview of the text

Download Implementation Pitfalls in Cryptography: Random Number Generation - Prof. Alexandra Boldyr and more Study notes Cryptography and System Security in PDF only on Docsity!

Implementation pitfalls

• We learned about various cryptographic primitives and the

provable security approach, saw many secure constructions.

• You are almost ready to employ this knowledge in practice.

• Let us review some common mistakes one needs to be aware

of and avoid when implementing cryptographic protocols.

1

Always remember to

• Use widely accepted and believed to be secure building blocks

(e.g. AES).

• Use provably secure (under reasonable assumptions)

constructions (e.g. $CBC).

• Do not assume that the schemes provide security properties

other than what is proven about them (e.g. encryption does

not provide authenticity).

• Realize that the use of a provably secure scheme does not

guarantee that the entire system will be secure.

• Make sure that you implement exactly the scheme that was

proven secure.

2

Not using the right primitives

• ATM-based passive optical networks commonly use a block

cipher called CHURN. It’s key size is 8 bits and it’s block size

is 4 bits!

• The use of the ECB mode and the Plain RSA encryption is still

very common.

Using the constructs without security proofs

3

One can prove that for every A making q queries there exists B s.t.

Is CTRS$ secure?

Not considering the security bounds

Let E:{0,1}

k !{0,1}

n !{0,1}

n be a block cipher.

R"{0,1}

L

E

K

C[1]

E

K

C[2]

E

K

C[m]

R||<1> (^) R||<2> R||

M[1]^ M[2]^ M[m]

R

Consider the encryption algorithm of a scheme CTRS$[L]

Kohno 3

8. 2 Using a construct without proofs of security

There have been numerous cryptographic protocols, like encryption schemes and MACs, that did

not come with proofs of security. That’s not surprising since people did not start to prove the

security of block cipher-based encryption schemes and MACs until the 1990 s. What is unfortunate

is that, without proofs of security, it is impossible to know whether a construction is actually secure

or not. In fact, in the exercises you have already been asked to find attacks against constructions

that do not come with proofs of security, even if they might appear secure at first sight.

Nowadays, many more people understand that it is important to use cryptographic protocols

that come with proofs of security. Still, it is not uncommon to find homebrew security software

using the ECB encryption mode, or something akin to CBCC. (We’ll get back to some examples

later.)

Hopefully, the discussions in Chapters 4 through 7 strongly motivate the fact that, whenever

possible, software applications should use constructions that are provably secure under reasonable

assumptions.

8. 3 Not considering the security bounds

Another common implementation pitfall is to not fully understand the security bounds in the proofs.

We saw a little bit of this when we discussed CBC$ with FEAL in Section 8 .1 of this chapter. But

now let’s consider the case where we actually believe that the underlying cryptographic primitive

is secure.

Let us define the encryption scheme CTRS$[L] = (K, E, D) with a block cipher E: { 0 , 1 }

k ×

n → { 0 , 1 }

n

. Here L is an integer between 1 and n − 1 , and is a parameter of our construction.

The key generation algorithm returns a randomly selected value from { 0 , 1 }

k

. The encryption algo-

rithm is shown below, and the decryption algorithm is defined in the natural way. This construction

is very similar to CTR$ from Chapter 5.

algorithm EK (M )

m ← %|M |/n&

If m ≥ 2 n−l then return ⊥

R

$ ← { 0 , 1 }

L

Pad ← EK (R‖〈 1 〉)‖EK (R‖〈 2 〉)‖ · · · EK (R‖〈m〉)

Pad ← the first |M | bits of Pad

C

′ ← M ⊕Pad

C ← R‖C

return C

Here 〈x〉 denotes the n − L-bit encoding of the integer x ∈ { 0 ,... , 2 n−L − 1 }.

We can prove the following result about the above construction.

Theorem 8.3.1 Let E: { 0 , 1 }

k × { 0 , 1 }

n → { 0 , 1 }

n be a family of functions, let L ∈ { 1 ,... , n − 1 }

be an integer, and let CTRS$[L] = (K, E, D) be the corresponding CTRS$[L] symmetric encryp-

tion scheme as described above. Let A be an adversary (for attacking the IND-CPA security of

CTRS$[L]) that runs in time at most t and asks at most q queries, these totaling at most σ n-bit

blocks. Then there exists an adversary B (attacking the PRF security of E) such that

Adv

ind-cpa

CTRS$[L]

(A) ≤ Adv

prf E

(B) +

q

2

L+

4

• WEP protocol for IEEE 802.11 wireless networks uses a

scheme like CTRS$ with L=24,40,64 or 80.

• Assume L=24 and q=4096. Then the last term becomes 1/

and no security is guaranteed by the bound!

Theorem 8.3.1 Let E: { 0 , 1 }

k

× { 0 , 1 }

n

n

be a family of functions, let L ∈ { 1 ,... , n − 1 }

be an integer, and let CTRS$[L] = (K, E, D) be the corresponding CTRS$[L] symmetric encryp-

tion scheme as described above. Let A be an adversary (for attacking the IND-CPA security of

CTRS$[L]) that runs in time at most t and asks at most q queries, these totaling at most σ n-bit

blocks. Then there exists an adversary B (attacking the PRF security of E) such that

Adv

ind-cpa

CTRS$[L]

(A) ≤ Adv

prf

E

(B) +

q

2

L+

5

Not using the right tool

• It is tempting to believe that encryption provide some

authenticity.

• The first versions of the SSH protocol, IPsec specification and

the WEP protocol did not use message authentication codes,

and thus were subject to certain attacks.

• A slightest tweak to a provably-secure scheme can make it

insecure

• Diebold voting machines encrypted the votes with CBC$, but

used all-zero string as an IV.

• Microsoft Word and Excel used CBCS$, but did not pick a new

random R each time.

Not implementing exactly the provable-secure schemes

6

Random numbers

• It is usually straightforward to implement the pseudo-code

descriptions in C or Java.

• However, how do you implement commands like^?

• The C offers a built-in random number generator, that works

roughly as this

6 IMPLEMENTATION PITFALLS

Given this description, and a description of the block cipher E, any experienced C or Java program-

mer should be able to easily implement most parts of the above algorithms. This is because almost

all of the operations in the above pseudocode are common to all popular languages. For example,

the “←” operation corresponds to the standard assignment operator (“=” in C and Java). The

programmer might, however, be puzzled about how to implement the “

$

←” randomized assignment

operator from the lines

K

$

k

and

IV

$

n

It is worth thinking about how a programmer might instantiate the “

$

←” operation in C or Java.

In order to implement the algorithms exactly as described in the above pseudocode, the operation

$

←” must select bits independently and uniformly at random. If an implementation of CBC$

does not do this, then the implementation is not exactly the object described above and in Figure

5 .2. At a minimum, this means that the security of the software implementation of CBC$ does

not immediately follow from Theorem 5 .1 9. In the worst case, not only might the security of

the software implementation not follow from Theorem 5 .1 9 , but the software implementation may

actually be insecure.

The first problem is that it is hard for computers, which are inherently deterministic, to select

bits independently and uniformly at random. Therefore, people implementing cryptosystems are

left to approximate the

$

← operation as best they can. The second problem is that there are many

natural approaches for trying to implement the

$

← operation in C or Java, and some of these

approaches can actually yield an insecure implementation. We consider some example (flawed)

approaches for instantiating

$

← here.

8. 6. 1 The C random number generator

The C programming language has a built in “random number generator,” called rand. Associated

to rand is another function named srand. Therefore, a natural way to try to implement

$

← would

6 IMPLEMENTATION PITFALLS

Given this description, and a description of the block cipher E, any experienced C or Java program-

mer should be able to easily implement most parts of the above algorithms. This is because almost

all of the operations in the above pseudocode are common to all popular languages. For example,

the “←” operation corresponds to the standard assignment operator (“=” in C and Java). The

programmer might, however, be puzzled about how to implement the “

$ ←” randomized assignment

operator from the lines

K

$ ← { 0 , 1 }

k

and

IV

$ ← { 0 , 1 }

n .

It is worth thinking about how a programmer might instantiate the “

$ ←” operation in C or Java.

In order to implement the algorithms exactly as described in the above pseudocode, the operation

$ ←” must select bits independently and uniformly at random. If an implementation of CBC$

does not do this, then the implementation is not exactly the object described above and in Figure

5 .2. At a minimum, this means that the security of the software implementation of CBC$ does

not immediately follow from Theorem 5 .1 9. In the worst case, not only might the security of

the software implementation not follow from Theorem 5 .1 9 , but the software implementation may

actually be insecure.

The first problem is that it is hard for computers, which are inherently deterministic, to select

bits independently and uniformly at random. Therefore, people implementing cryptosystems are

left to approximate the

$ ← operation as best they can. The second problem is that there are many

natural approaches for trying to implement the

$ ← operation in C or Java, and some of these

approaches can actually yield an insecure implementation. We consider some example (flawed)

approaches for instantiating

$ ← here.

8. 6. 1 The C random number generator

The C programming language has a built in “random number generator,” called rand. Associated

to rand is another function named srand. Therefore, a natural way to try to implement

$ ← would

be to use rand and srand.

At a high level, the way a programmer is supposed to use rand and srand is as follows. The

program is first supposed to call srand(seed), where seed is the “seed” to the C random number

generator. After calling srand, the program can invoke rand() any number of times. Each time

rand() will return a value that is supposed to appear random. Therefore, a natural way for trying

to generate a large number of random bits is to invoke rand() as many times as necessary. Here

we ignore how the programmer picks seed.

Let us look under the hood and see how rand and srand work. Although different systems

implement these functions in slightly different ways, there is a lot of commonality between the

code for these functions on different systems. Below we show the code for srand and rand on one

popular system. For this system, state is a global 32 -bit unsigned integer. We do not present

actual C code, but try to capture as the essence of these functions in C-like pseudocode.

procedure srand(seed)

state = seed;

function rand()

state = ((state * 1103515245 ) + 12345 )

mod 2147483648 ;

return state

32-bit number

2 31

7

• So one can implement^ as follows

• But looking at how rand() works we notice that

• This means that there are still only^2

32

possibilities for the key.

Kohno 7

Here 2147483648 is 2

31 .

Let us now consider how a programmer might use rand to implement the CBC$ encryption

scheme’s key generation algorithm. We show our traditional pseudocode on the left, and a C-like

pseudocode on the right.

algorithm K

K

$ ← { 0 , 1 } k

return K

function keygen()

key = rand();

return key

The first observation that we make is that, since rand returns a 32 -bit integer, key must also be

a 32 -bit integer. If k > 32 , then the implementation would clearly not be using a key selected

randomly from the set of all strings k-bit strings { 0 , 1 } k

. The security implications of this should

be clear. While we consider it impractical to exhaustively search a randomly selected 128 -bit AES

key, it would be practical to exhaustively search a 32 -bit key generated via the above keygen code.

To fix the problem, one might try invoking rand() multiple times. For example, if the block

cipher is AES with k = 128 , the above pseudocode might change to:

algorithm K

K

$ ← { 0 , 1 }

128

return K

function keygen()

key[ 0 ] = rand(); key[ 1 ] = rand();

key[ 2 ] = rand(); key[ 3 ] = rand();

return key

where key is a now a four-element array of 32 -bit unsigned integers.

But there is still something seriously wrong with the above implementation of keygen that

could compromise the security of CBC$. To see the problem, let us return to how rand works. By

looking at how rand works, we find that

key[ 1 ] = ((key[ 0 ] · 1103515245 ) + 12345 ) mod 2

31

key[ 2 ] = ((((key[ 0 ] · 1103515245 ) + 12345 ) · 1103515245 ) +

12345 ) mod 2

31

key[ 3 ] = ((((((key[ 0 ] · 1103515245 ) + 12345 ) · 1103515245 ) +

12345 ) · 1103515245 ) + 12345 ) mod 2

31

This means that now, even though key is now a 128 -bit value (an array of four 32 -bit elements),

there are only 2

32 possibilities for key. An adversary could therefore exhaustively search key using

at most 2 32 tries.

8. 6. 2 Key generation and the Netscape browser

¿From the above discussion, it should be clear that there are serious problems in one of the most

natural approaches for trying to generate random numbers in software (using rand). There are two

problems with rand. First, the state variable of rand is only 32 -bits long, which means that the

state can be exhaustively search using reasonable resources. Second, knowing one value of state

(e.g., Key[ 0 ]) allows us to compute all previous or subsequent outputs of rand (e.g., Key[ 1 ],

Key[ 2 ], and Key[ 3 ]).

Rather than use (rand), another natural approach for trying to create random numbers is to

6 IMPLEMENTATION PITFALLS

Given this description, and a description of the block cipher E, any experienced C or Java program-

mer should be able to easily implement most parts of the above algorithms. This is because almost

all of the operations in the above pseudocode are common to all popular languages. For example,

the “←” operation corresponds to the standard assignment operator (“=” in C and Java). The

programmer might, however, be puzzled about how to implement the “

$

←” randomized assignment

operator from the lines

K

$

k

and

IV

$

n

It is worth thinking about how a programmer might instantiate the “

$

←” operation in C or Java.

In order to implement the algorithms exactly as described in the above pseudocode, the operation

$

←” must select bits independently and uniformly at random. If an implementation of CBC$

does not do this, then the implementation is not exactly the object described above and in Figure

5 .2. At a minimum, this means that the security of the software implementation of CBC$ does

not immediately follow from Theorem 5 .1 9. In the worst case, not only might the security of

the software implementation not follow from Theorem 5 .1 9 , but the software implementation may

actually be insecure.

The first problem is that it is hard for computers, which are inherently deterministic, to select

bits independently and uniformly at random. Therefore, people implementing cryptosystems are

left to approximate the

$

← operation as best they can. The second problem is that there are many

natural approaches for trying to implement the

$

← operation in C or Java, and some of these

approaches can actually yield an insecure implementation. We consider some example (flawed)

approaches for instantiating

$

← here.

8. 6. 1 The C random number generator

The C programming language has a built in “random number generator,” called rand. Associated

to rand is another function named srand. Therefore, a natural way to try to implement

$

← would

be to use rand and srand.

At a high level, the way a programmer is supposed to use rand and srand is as follows. The

program is first supposed to call srand(seed), where seed is the “seed” to the C random number

generator. After calling srand, the program can invoke rand() any number of times. Each time

Kohno 7

Here 2147483648 is 2

31 .

Let us now consider how a programmer might use rand to implement the CBC$ encryption

scheme’s key generation algorithm. We show our traditional pseudocode on the left, and a C-like

pseudocode on the right.

algorithm K

K

$ ← { 0 , 1 }

k

return K

function keygen()

key = rand();

return key

The first observation that we make is that, since rand returns a 32 -bit integer, key must also be

a 32 -bit integer. If k > 32 , then the implementation would clearly not be using a key selected

randomly from the set of all strings k-bit strings { 0 , 1 } k

. The security implications of this should

be clear. While we consider it impractical to exhaustively search a randomly selected 128 -bit AES

key, it would be practical to exhaustively search a 32 -bit key generated via the above keygen code.

To fix the problem, one might try invoking rand() multiple times. For example, if the block

cipher is AES with k = 128 , the above pseudocode might change to:

algorithm K

K

$ ← { 0 , 1 } 128

return K

function keygen()

key[ 0 ] = rand(); key[ 1 ] = rand();

key[ 2 ] = rand(); key[ 3 ] = rand();

return key

where key is a now a four-element array of 32 -bit unsigned integers.

But there is still something seriously wrong with the above implementation of keygen that

could compromise the security of CBC$. To see the problem, let us return to how rand works. By

looking at how rand works, we find that

key[ 1 ] = ((key[ 0 ] · 1103515245 ) + 12345 ) mod 2

31

key[ 2 ] = ((((key[ 0 ] · 1103515245 ) + 12345 ) · 1103515245 ) +

12345 ) mod 2 31

key[ 3 ] = ((((((key[ 0 ] · 1103515245 ) + 12345 ) · 1103515245 ) +

12345 ) · 1103515245 ) + 12345 ) mod 2

31

This means that now, even though key is now a 128 -bit value (an array of four 32 -bit elements),

there are only 2

32 possibilities for key. An adversary could therefore exhaustively search key using

at most 2 32 tries.

    1. 2 Key generation and the Netscape browser

¿From the above discussion, it should be clear that there are serious problems in one of the most

natural approaches for trying to generate random numbers in software (using rand). There are two

problems with rand. First, the state variable of rand is only 32 -bits long, which means that the

state can be exhaustively search using reasonable resources. Second, knowing one value of state

(e.g., Key[ 0 ]) allows us to compute all previous or subsequent outputs of rand (e.g., Key[ 1 ],

Key[ 2 ], and Key[ 3 ]).

Rather than use (rand), another natural approach for trying to create random numbers is to

try to exploit properties of believed-to-be secure cryptographic objects, like AES or SHA 1. This is

8