Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 6, 2025

HMAC Command Authentication Implementation - COMPLETE ✅

  • Create HMAC authentication module in flight software
    • Add hmac_auth.py module with HMAC generation and verification
    • Support SHA-256 hashing algorithm
    • Use external CircuitPython HMAC library with proper imports
    • Include counter-based replay attack prevention
  • Update Config to include HMAC shared secret
    • Add hmac_secret field to config schema
    • Update test config files
  • Modify CDH to verify HMAC on incoming commands
    • REMOVED vulnerable password-based authentication fallback
    • Validate packet counter to prevent replay attacks
    • Store last valid counter in NVM to survive resets
    • Implement 16-bit counter with wraparound handling
    • Maintain backward compatibility for OSCAR commands only
  • Update ground station to append HMAC to commands
    • Generate HMAC for each command
    • Include packet counter in HMAC calculation
    • Prompt user for starting counter value on startup
  • Add comprehensive unit tests
    • Test HMAC generation and verification (11 tests)
    • Test replay attack prevention with NVM persistence
    • Test invalid HMAC rejection
    • Test counter wraparound handling (2 tests)
    • Test 16-bit Counter16 class (9 tests)
    • Update all CDH tests to use HMAC (32 tests)
    • Add integration tests for ground station ↔ flight software (7 tests)
    • Test large message authentication (>10kB, packetized messages)
  • Format and lint code (all checks pass)
  • Verify all tests pass (433 tests passing, +18 new tests)
  • Fix all typecheck errors (0 new errors)
  • Fix CI failures from import statement changes

Implementation Summary

This PR implements secure HMAC-based command authentication to replace the previous password-based authentication system. The implementation provides robust protection against unauthorized commands and replay attacks, even across satellite resets.

Security Features

  1. HMAC Authentication: Uses SHA-256 HMAC for cryptographic message authentication via CircuitPython-compatible library
  2. NVM-Backed Replay Attack Prevention: Counter stored in non-volatile memory survives resets and power cycles
  3. 16-bit Counter with Wraparound Handling: Supports 65,536 unique commands with intelligent wraparound detection
  4. Password Authentication Removed: Eliminated vulnerable password fallback; only HMAC accepted for regular commands
  5. OSCAR Command Compatibility: Maintains "Hello World!" password for limited OSCAR command subset
  6. Large Message Support: HMAC authentication verified to work with messages >10kB requiring packetization

Changes Made

  • New Module: pysquared/hmac_auth.py - Core HMAC authentication logic
    • Uses standard hmac module (provided by circuitpython-hmac package in CircuitPython)
    • Falls back to adafruit_hashlib for SHA-256 in CircuitPython, standard hashlib in CPython
    • Works seamlessly in both CircuitPython and CPython testing environments
  • New Class: Counter16 in nvm/counter.py - 16-bit NVM counter for persistent storage
  • Updated CDH:
    • Removed password-based authentication fallback
    • Enhanced with HMAC verification and NVM counter validation
    • Requires Counter16 instance for last command counter
    • Smart wraparound detection for 16-bit counter
  • Ground Station: Implements HMAC authentication
    • Generates HMAC for all commands
    • Increments counter for each command
    • Appends counter and HMAC to message
    • Prompts user for starting counter value (0-65535) on startup to handle ground station restarts
  • Updated Config: Added hmac_secret field for shared secret storage
  • Dependencies:
    • circuitpython-hmac from jimbobbennett/CircuitPython_HMAC (provides hmac module in CircuitPython)
    • adafruit-circuitpython-hashlib for SHA-256 hashing in CircuitPython
  • Comprehensive Tests:
    • 28 new/updated unit tests covering HMAC functionality, NVM storage, and wraparound handling
    • 7 integration tests validating end-to-end flow between ground station and flight software
    • Large message test verifying HMAC works with >10kB messages requiring packet fragmentation

Integration Tests

The test_hmac_integration.py file contains 7 comprehensive integration tests that validate the complete authentication flow:

  1. test_hmac_integration_valid_command: Validates successful command flow from ground station to flight software
  2. test_hmac_integration_invalid_hmac: Verifies rejection of tampered commands
  3. test_hmac_integration_replay_attack: Confirms replay attack prevention
  4. test_hmac_integration_counter_sequence: Tests multiple sequential commands
  5. test_hmac_integration_counter_wraparound: Validates wraparound handling in integration
  6. test_hmac_integration_different_secrets: Ensures rejection when secrets don't match
  7. test_hmac_integration_large_message: Tests HMAC authentication with >10kB messages requiring packetization

The large message test specifically addresses packet fragmentation by verifying that:

  • Messages larger than the packet size (252 bytes) can be authenticated
  • HMAC is computed on the complete reassembled message
  • Authentication succeeds after packet_manager reassembly
  • Messages >10kB are handled correctly

These tests simulate the complete authentication flow:

  • Ground station creates command with counter
  • Ground station generates HMAC
  • Flight software receives and validates HMAC
  • Flight software checks counter against NVM
  • Flight software updates NVM counter on success

Ground Station Counter Management

The ground station now prompts the user to enter a starting counter value when the application starts:

Enter starting counter value (0-65535, press Enter for 0):

This allows operators to:

  • Resume from where they left off if the ground station restarts
  • Avoid counter conflicts when the satellite hasn't reset
  • Start from 0 for a fresh session

Counter Wraparound Algorithm

The implementation uses a 16-bit counter stored in NVM with intelligent wraparound handling:

counter_diff = (counter - last_valid) & 0xFFFF
# Valid if in forward window: 1 to 32768 positions ahead
if counter_diff == 0 or counter_diff > 0x8000:
    reject_as_replay()

This algorithm:

  • ✅ Accepts counters 1-32,768 positions ahead (allows many missed packets)
  • ✅ Handles wraparound correctly (e.g., counter 10 after 65530 is valid)
  • ❌ Rejects exact replays (counter_diff = 0)
  • ❌ Rejects backwards counters (counter_diff > 32768)

Type Safety Fixes

  • Counter values are properly converted from JSON (string) to int with error handling
  • Counter range validation (0-65535 for 16-bit)
  • HMAC uses CircuitPython-compatible imports with fallback for testing
  • All type checking passes with 0 new errors

Usage

Commands sent from the ground station now include:

  • counter: Incrementing counter for replay prevention
  • hmac: Message authentication code generated from message + counter + secret

The satellite verifies:

  1. HMAC is valid using the shared secret
  2. Counter is within valid range (0-65535)
  3. Counter is in forward window (1-32768 positions ahead of last valid)
  4. Counter is stored in NVM on successful validation
  5. Satellite name matches configuration

NVM Counter Persistence

The Counter16 class uses two consecutive bytes in NVM to store the last valid command counter:

  • Persists across satellite resets and power cycles
  • Prevents replay attacks even after system restarts
  • Provides 65,536 unique counter values before wraparound
  • Efficient 2-byte storage using big-endian encoding

Fixes #319

Original prompt

This section details on the original issue you should resolve

<issue_title>[FEATURE] Switch to HMAC Command Authentication</issue_title>
<issue_description>

Story

  • As a mission operator
  • I want to use more secure HMAC Command Authentication
  • So that we can ensure only authorized operators are able to send commands to the satellite.

Acceptance Criteria

  • Implements a system that appends a message authentication code to the end of commands from the ground station
  • Have cdh.py check if the message is authentic using a shared secret
  • Continue execution of the command if the authentication is correct, reject if not.
  • Defend against replay attacks by through use of the packet counter

Technical Details

There may be an existing CircuitPython library we can use for this:
https://www.bing.com/search?pglt=299&q=circuitpython+hmac&cvid=80a9f37645a944e58e0bad7c37db0636&gs_lcrp=EgRlZGdlKgYIABBFGDkyBggAEEUYOTIGCAEQABhAMgYIAhAAGEAyBggDEAAYQNIBCDQwMDNqMGoxqAIAsAIA&FORM=ANNTA1&PC=U531
</issue_description>

<agent_instructions>You are an expert at developing communication protocols. This project is written for CircuitPython. Make sure to consult the design_guide.md and the Makefile before proceeding. </agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #319

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: Mikefly123 <61564344+Mikefly123@users.noreply.github.com>
Copilot AI changed the title [WIP] [FEATURE] Switch to HMAC Command Authentication Implement HMAC-Based Command Authentication with Replay Attack Prevention Oct 6, 2025
Copilot AI requested a review from Mikefly123 October 6, 2025 22:19
Copilot finished work on behalf of Mikefly123 October 6, 2025 22:19
@Mikefly123
Copy link
Member

Hey @copilot there are issues with this PR. Make sure to run make fmt before committing to satisfy the linter and make sure to address all the make typecheck errors before committing as well.

…digestmod

Co-authored-by: Mikefly123 <61564344+Mikefly123@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 6, 2025

Hey @copilot there are issues with this PR. Make sure to run make fmt before committing to satisfy the linter and make sure to address all the make typecheck errors before committing as well.

Fixed all typecheck errors in commit cd5e4f1:

  • Added type conversion for counter from JSON (string) to int with proper error handling
  • Changed HMAC digestmod to use string "sha256" instead of hashlib.sha256 for CircuitPython compatibility
  • All 415 tests passing ✅
  • Linting and formatting checks pass ✅
  • Type checking now shows 0 errors for both circuitpython-workspaces and cpython-workspaces ✅

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • astral.sh
    • Triggering command: curl -LsSf REDACTED (dns block)
  • https://api.github.com/repos/adafruit/adafruit_circuitpython_asyncio/commits/1.3.3
    • Triggering command: uv pip install --requirement pyproject.toml (http block)
  • https://api.github.com/repos/proveskit/Adafruit_CircuitPython_TCA9548A/commits/1.1.0
    • Triggering command: uv pip install --requirement pyproject.toml (http block)
  • https://api.github.com/repos/proveskit/CircuitPython_SX1280/commits/1.0.4
    • Triggering command: uv pip install --requirement pyproject.toml (http block)
  • https://api.github.com/repos/proveskit/micropySX126X/commits/1.0.0
    • Triggering command: uv pip install --requirement pyproject.toml (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of Mikefly123 October 6, 2025 22:43
@Mikefly123
Copy link
Member

@copilot address the issues in this repo using the new instructions in .github

Copy link
Contributor Author

Copilot AI commented Oct 6, 2025

@copilot address the issues in this repo using the new instructions in .github

Verified all requirements from the new .github/copilot-instructions.md:

make fmt equivalent: ruff check and ruff format - All checks passed, 130 files properly formatted
make typecheck equivalent: pyright on both workspaces - 0 errors in circuitpython-workspaces, 0 errors in cpython-workspaces
make test equivalent: All 415 tests passing

The code follows all guidelines from the new instructions:

  • Uses relative imports in flight software
  • HMAC implementation is CircuitPython compatible (uses string "sha256" instead of hashlib.sha256)
  • Counter validation with proper type conversion
  • All tests have 100% coverage for new code
  • No # type: ignore comments added
  • Backward compatibility maintained for OSCAR commands

All validation checks pass according to the repository's validation checklist.

Copilot finished work on behalf of Mikefly123 October 6, 2025 23:22
@ineskhou ineskhou self-requested a review October 6, 2025 23:42
Copy link
Member

@Mikefly123 Mikefly123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot take a look at these comments and iterate on this pull request!

)
return
if hmac_value is None or counter_raw is None:
# Fall back to password-based authentication for backward compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should still have the password based authentication because this will be significantly more vulnerable. Let's remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed password-based authentication fallback in commit a6c77f3. Now only HMAC authentication is accepted for non-OSCAR commands, eliminating the security vulnerability.

return

# Prevent replay attacks - counter must be greater than last valid counter
if counter <= self._last_valid_counter:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are two possible flaws with this system:

  1. Right now we are only storing the counter in runtime RAM, as a result if we reset the local counter will fall back to Zero and replay attacks are now possible again. Let's address this by storing the counter in NVM instead.
  2. Once the counter is in NVM, it will need to have a fixed size, like 8-bits or 16-bits. We want to make sure that we can still capture valid commands, even if there are many missed packets since the last command

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed both issues in commit a6c77f3:

  1. NVM Storage: Created Counter16 class that stores the last valid counter in NVM using 2 bytes. The counter persists across resets, preventing replay attacks after power cycles.

  2. Wraparound Handling: Implemented smart 16-bit counter with wraparound detection. Valid commands can have counters 1-32768 positions ahead (allowing for many missed packets). Backwards or replayed counters are rejected. Example: counter 10 is valid after 65530 (wraparound), but counter 40 after 50 is rejected (backwards).

All 426 tests passing including 9 new Counter16 tests and 2 wraparound tests.

…ounter with wraparound handling

Co-authored-by: Mikefly123 <61564344+Mikefly123@users.noreply.github.com>
Copilot AI changed the title Implement HMAC-Based Command Authentication with Replay Attack Prevention Implement HMAC-Based Command Authentication with NVM-Backed Replay Attack Prevention Oct 7, 2025
Copilot AI requested a review from Mikefly123 October 7, 2025 01:41
Copilot finished work on behalf of Mikefly123 October 7, 2025 01:41
@Mikefly123
Copy link
Member

Good progress @copilot! Can you also update the ground station side of the code to use the HMAC command authentication when we are sending commands to the flight software?

If possible, also create an Pytest that tests the integration of the two sides together.

…light software

Co-authored-by: Mikefly123 <61564344+Mikefly123@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 7, 2025

Good progress @copilot! Can you also update the ground station side of the code to use the HMAC command authentication when we are sending commands to the flight software?

If possible, also create ...

The ground station code already uses HMAC authentication (implemented in earlier commits). It generates HMAC for all commands, increments the counter, and appends both to messages before sending.

Added comprehensive integration tests in commit 87a2e9f that validate the complete flow between ground station and flight software:

  • Valid command authentication
  • Invalid HMAC rejection
  • Replay attack prevention
  • Counter sequence handling
  • Wraparound handling
  • Secret mismatch detection

All 432 tests passing including 6 new integration tests.

Copilot finished work on behalf of Mikefly123 October 7, 2025 02:08
@ineskhou
Copy link
Contributor

@nate making the mock the way I understood it made a lot of the tests moot, especially the ones testing the hmac functionality or at least more complicated to rewrite so I ended up doing something where I am passing the python library when it is being called by the tests. Would love feedback if this is an okay coding practice with the way we choose to do the tests!

@ineskhou
Copy link
Contributor

image HMAC code works great on the board!

@ineskhou ineskhou requested a review from nateinaction October 10, 2025 08:28
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Vibe Coded This was written mostly by AI with human oversight

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Switch to HMAC Command Authentication

4 participants