@@ -77,6 +77,18 @@ def batch_start_from_time(time):
7777 return (int (time .timestamp ()) // SECONDS_PER_BATCH ) * SECONDS_PER_BATCH
7878
7979
80+ def secure_shuffle (items ):
81+ """Perform a cryptographically secure shuffling of the given items
82+
83+ Args:
84+ items (obj:list): A list of items to be shuffled
85+
86+ Returns:
87+ Nothing. Items are shuffled in place
88+ """
89+ random .shuffle (items , secrets .SystemRandom ().random )
90+
91+
8092#########################################
8193### BASIC CRYPTOGRAPHIC FUNCTIONALITY ###
8294#########################################
@@ -130,8 +142,7 @@ def generate_ephids_for_day(current_day_key, shuffle=True):
130142
131143 # Shuffle the resulting ephids
132144 if shuffle :
133- # WARNING: replace with a secure shuffle
134- random .shuffle (ephids )
145+ secure_shuffle (ephids )
135146
136147 return ephids
137148
@@ -310,7 +321,7 @@ def add_observation(self, ephid, time):
310321 self .observations [batch_start ].append (ephid )
311322
312323 # Shuffle observations to hide receive order
313- random . shuffle (self .observations [batch_start ])
324+ secure_shuffle (self .observations [batch_start ])
314325
315326 def get_tracing_information (
316327 self ,
@@ -451,4 +462,4 @@ def housekeeping_after_batch(self, batch):
451462 self .observations [day_time ].extend (observations )
452463
453464 # Reshuffle to make sure we do not store ordering data
454- random . shuffle (self .observations [day_time ])
465+ secure_shuffle (self .observations [day_time ])
0 commit comments