summaryrefslogtreecommitdiff
path: root/pipermail/pycrypto/2013q4/000702.html
blob: 3dce765f06e3ed568b991938fd445cb4b59ac22e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
 <HEAD>
   <TITLE> [pycrypto] CVE-2013-1445 python-crypto: PRNG not correctly reseeded in some situations
   </TITLE>
   <LINK REL="Index" HREF="index.html" >
   <LINK REL="made" HREF="mailto:pycrypto%40lists.dlitz.net?Subject=Re%3A%20%5Bpycrypto%5D%20CVE-2013-1445%20python-crypto%3A%20PRNG%20not%20correctly%20reseeded%0A%20in%20some%20situations&In-Reply-To=%3C20131017162841.GA22758%40rivest.dlitz.net%3E">
   <META NAME="robots" CONTENT="index,nofollow">
   <style type="text/css">
       pre {
           white-space: pre-wrap;       /* css-2.1, curent FF, Opera, Safari */
           }
   </style>
   <META http-equiv="Content-Type" content="text/html; charset=us-ascii">
   <LINK REL="Previous"  HREF="000704.html">
   <LINK REL="Next"  HREF="000705.html">
 </HEAD>
 <BODY BGCOLOR="#ffffff">
   <H1>[pycrypto] CVE-2013-1445 python-crypto: PRNG not correctly reseeded in some situations</H1>
    <B>Dwayne Litzenberger</B> 
    <A HREF="mailto:pycrypto%40lists.dlitz.net?Subject=Re%3A%20%5Bpycrypto%5D%20CVE-2013-1445%20python-crypto%3A%20PRNG%20not%20correctly%20reseeded%0A%20in%20some%20situations&In-Reply-To=%3C20131017162841.GA22758%40rivest.dlitz.net%3E"
       TITLE="[pycrypto] CVE-2013-1445 python-crypto: PRNG not correctly reseeded in some situations">dlitz at dlitz.net
       </A><BR>
    <I>Thu Oct 17 09:28:41 PDT 2013</I>
    <P><UL>
        <LI>Previous message: <A HREF="000704.html">[pycrypto] PyCrypto status update &amp; release plans
</A></li>
        <LI>Next message: <A HREF="000705.html">[pycrypto] RSA exportKey() changes set in stone for 2.7?
</A></li>
         <LI> <B>Messages sorted by:</B> 
              <a href="date.html#702">[ date ]</a>
              <a href="thread.html#702">[ thread ]</a>
              <a href="subject.html#702">[ subject ]</a>
              <a href="author.html#702">[ author ]</a>
         </LI>
       </UL>
    <HR>  
<!--beginarticle-->
<PRE>In PyCrypto before v2.6.1, the Crypto.Random pseudo-random number
generator (PRNG) exhibits a race condition that may cause it to generate
the same 'random' output in multiple processes that are forked from each
other.  Depending on the application, this could reveal sensitive
information or cryptographic keys to remote attackers.

An application may be affected if, within 100 milliseconds, it performs
the following steps (which may be summarized as &quot;read-fork-read-read&quot;):

1. Read from the Crypto.Random PRNG, causing an internal reseed;
2. Fork the process and invoke Crypto.Random.atfork() in the child;
3. Read from the Crypto.Random PRNG again, in at least two different
     processes (parent and child, or multiple children).

Only applications that invoke Crypto.Random.atfork() and perform the
above steps are affected by this issue.  Other applications are
unaffected.

Note: Some PyCrypto functions, such as key generation and PKCS#1-related
functions, implicitly read from the Crypto.Random PRNG.

== Technical details ==

Crypto.Random uses Fortuna[1] to generate random numbers.  The flow of
entropy looks something like this:

      /dev/urandom  -\
                      +-&gt; &quot;accumulator&quot; --&gt; &quot;generator&quot; --&gt; output
      other sources -/   (entropy pools)     (AES-CTR)

- The &quot;accumulator&quot; maintains several pools that collect entropy from
    the environment.

- The &quot;generator&quot; is a deterministic PRNG that is reseeded by the
    accumulator.  Reseeding normally occurs during each request for random
    numbers, but never more than once every 100 ms (the &quot;minimum reseed
    interval&quot;).

When a process is forked, the parent's state is duplicated in the child.
In order to continue using the PRNG, the child process must invoke
Crypto.Random.atfork(), which collects new entropy from /dev/urandom and
adds it to the accumulator.  When new PRNG output is subsequently
requested, some of the new entropy in the accumulator is used to reseed
the generator, causing the output of the child to diverge from its
parent.

However, in previous versions of PyCrypto, Crypto.Random.atfork() did
not explicitly reset the child's rate-limiter, so if the child requested
PRNG output before the minimum reseed interval of 100 ms had elapsed, it
would generate its output using state inherited from its parent.

This created a race condition between the parent process and its forked
children that could cause them to produce identical PRNG output for the
duration of the 100 ms minimum reseed interval.

== Demonstration ==

Here is some sample code that illustrates the problem:

      from binascii import hexlify
      import multiprocessing, pprint, time
      import Crypto.Random

      def task_main(arg):
          a = Crypto.Random.get_random_bytes(8)
          time.sleep(0.1)
          b = Crypto.Random.get_random_bytes(8)
          rdy, ack = arg
          rdy.set()
          ack.wait()
          return &quot;%s,%s&quot; % (hexlify(a).decode(),
                            hexlify(b).decode())

      n_procs = 4
      manager = multiprocessing.Manager()
      rdys = [manager.Event() for i in range(n_procs)]
      acks = [manager.Event() for i in range(n_procs)]
      Crypto.Random.get_random_bytes(1)
      pool = multiprocessing.Pool(processes=n_procs,
                                  initializer=Crypto.Random.atfork)
      res_async = pool.map_async(task_main, zip(rdys, acks))
      pool.close()
      [rdy.wait() for rdy in rdys]
      [ack.set() for ack in acks]
      res = res_async.get()
      pprint.pprint(sorted(res))
      pool.join()

The output should be random, but it looked like this:

      ['c607803ae01aa8c0,2e4de6457a304b34',
       'c607803ae01aa8c0,af80d08942b4c987',
       'c607803ae01aa8c0,b0e4c0853de927c4',
       'c607803ae01aa8c0,f0362585b3fceba4']

== Solution ==

The solution is to upgrade to PyCrypto v2.6.1 or later, which properly
resets the rate-limiter when Crypto.Random.atfork() is invoked in the
child.

== Files ==

PyCrypto v2.6.1 may be downloaded from the PyCrypto website[2], from 
PyPI, or using your operating system's package manager or ports tree.  

The official tarball has the following SHA256 sums:

f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c *pycrypto-2.6.1.tar.gz
c2ab0516cc55321e6543ae75e2aa6f6e56e97432870f32a7799f3b89f467dc1b *pycrypto-2.6.1.tar.gz.asc

The git repository is here: <A HREF="https://github.com/dlitz/pycrypto/">https://github.com/dlitz/pycrypto/</A>
The v2.6.1 tag id is: ebb470d3f0982702e3e9b7fb9ebdaeed95903aaf
The v2.6.1 commit id is: 7fd528d03b5eae58eef6fd219af5d9ac9c83fa50

For informational purposes, patches against pycrypto v2.6 and v2.1.0 are 
attached.  Distributors patching older versions of the library, please 
remember to run the test suite before releasing a modified package:

    # From the source tree
    python setup.py build test

    # After installation
    python -m Crypto.SelfTest.__init__

== Thanks ==

Thanks to Yves-Alexis Perez and Sebastian Ramacher for helping to 
coordinate the release of this fix.

== References ==

[1] N. Ferguson and B. Schneier, _Practical Cryptography_,
      Indianapolis: Wiley, 2003, pp. 155-184.

[2] <A HREF="https://www.dlitz.net/software/pycrypto/">https://www.dlitz.net/software/pycrypto/</A> or <A HREF="http://www.pycrypto.org/">http://www.pycrypto.org/</A>

-- 
Dwayne C. Litzenberger &lt;<A HREF="http://lists.dlitz.net/cgi-bin/mailman/listinfo/pycrypto">dlitz at dlitz.net</A>&gt;
    OpenPGP: 19E1 1FE8 B3CF F273 ED17  4A24 928C EC13 39C2 5CF7
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CVE-2013-1445-pycrypto2.6.patch
Type: text/x-diff
Size: 13972 bytes
Desc: not available
URL: &lt;<A HREF="http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0002.patch">http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0002.patch</A>&gt;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CVE-2013-1445-pycrypto2.1.0.patch
Type: text/x-diff
Size: 10453 bytes
Desc: not available
URL: &lt;<A HREF="http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0003.patch">http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0003.patch</A>&gt;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 222 bytes
Desc: Digital signature
URL: &lt;<A HREF="http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0001.sig">http://lists.dlitz.net/pipermail/pycrypto/attachments/20131017/05f461ef/attachment-0001.sig</A>&gt;
</PRE>




<!--endarticle-->
    <HR>
    <P><UL>
        <!--threads-->
	<LI>Previous message: <A HREF="000704.html">[pycrypto] PyCrypto status update &amp; release plans
</A></li>
	<LI>Next message: <A HREF="000705.html">[pycrypto] RSA exportKey() changes set in stone for 2.7?
</A></li>
         <LI> <B>Messages sorted by:</B> 
              <a href="date.html#702">[ date ]</a>
              <a href="thread.html#702">[ thread ]</a>
              <a href="subject.html#702">[ subject ]</a>
              <a href="author.html#702">[ author ]</a>
         </LI>
       </UL>

<hr>
<a href="http://lists.dlitz.net/cgi-bin/mailman/listinfo/pycrypto">More information about the pycrypto
mailing list</a><br>
</body></html>