

Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
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
1 / 3
This page cannot be seen from the preview
Don't miss anything!


1
2
3
One can prove that for every A making q queries there exists B s.t.
Is CTRS$ secure?
Let E:{0,1}
k !{0,1}
n !{0,1}
n be a block cipher.
C[m]
R||<1> (^) R||<2> R||
M[1]^ M[2]^ M[m]
Consider the encryption algorithm of a scheme CTRS$[L]
Kohno 3
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.
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 ⊥
$ ← { 0 , 1 }
L
Pad ← EK (R‖〈 1 〉)‖EK (R‖〈 2 〉)‖ · · · EK (R‖〈m〉)
Pad ← the first |M | bits of Pad
′ ← M ⊕Pad
′
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
q
2
L+
4
k
n
n
CTRS$[L]
prf
E
2
L+
5
6
$
$
k
$
n
$
$
$
$
$
$
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
$ ← { 0 , 1 }
k
and
$ ← { 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.
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
32
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
$ ← { 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
$ ← { 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.
¿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
$
$
k
$
n
$
$
$
$
$
$
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
$ ← { 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
$ ← { 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.
¿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