Last active
November 17, 2025 07:33
-
-
Save atc1441/41af75048e4c22af1f5f0d4c1d94bb56 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdint.h> | |
| // Philips Sonicare NFC Head Password calculation by @atc1441 Video manual: https://www.youtube.com/watch?v=EPytrn8i8sc | |
| uint16_t CRC16(uint16_t crc, uint8_t *buffer, int len) // Default CRC16 Algo | |
| { | |
| while(len--) | |
| { | |
| crc ^= *buffer++ << 8; | |
| int bits = 0; | |
| do | |
| { | |
| if ( (crc & 0x8000) != 0 ) | |
| crc = (2 * crc) ^ 0x1021; | |
| else | |
| crc *= 2; | |
| } | |
| while ( ++bits < 8 ); | |
| } | |
| return crc; | |
| } | |
| uint8_t nfctag_uid[] = {0x04,0xEC,0xFC,0xA2,0x94,0x10,0x90}; // NTAG UID | |
| uint8_t nfc_second[] = "221214 12K"; // Head MFG String, printed on Head and at memory location 0x23 | |
| int main() | |
| { | |
| uint32_t crc_calc = CRC16(0x49A3, nfctag_uid, 7); // Calculate the NTAG UID CRC | |
| crc_calc = crc_calc | (CRC16(crc_calc, nfc_second, 10) << 16); // Calculate the MFG CRC | |
| crc_calc = (crc_calc >> 8) & 0x00FF00FF | (crc_calc << 8) & 0xFF00FF00; // Rotate the uin16_t bytes | |
| printf("by @ATC1441 NFC CRC : 0x%08X expected: 0x61F0A50F\r\n", crc_calc);// Print out the calucated password | |
| return 0; | |
| } |
import argparse
from typing import List
def crc16(crc: int, buffer: List[int]) -> int:
"""
Calculates the CRC-16 value for a given buffer.
Args:
crc: The initial CRC value.
buffer: A list of integers representing the data buffer.
Returns:
The calculated CRC-16 value.
"""
for byte in buffer:
crc ^= byte << 8
for _ in range(8):
if crc & 0x8000:
crc = (crc << 1) ^ 0x1021 # CRC-16-CCITT polynomial
else:
crc <<= 1
return crc & 0xFFFF
def compute_password(uid: List[int], nfc_second: bytes) -> str:
"""
Computes the password for a Philips Sonicare NFC device.
Args:
uid: A list of integers representing the NTAG UID.
nfc_second: A bytes object representing the head manufacturing string.
Returns:
A string representing the computed password in hexadecimal format.
"""
# Initial CRC value for NTAG UID
crc_calc = crc16(0x49A3, uid)
# Calculate the MFG CRC and combine with NTAG UID CRC
crc_calc |= crc16(crc_calc, list(nfc_second)) << 16
# Rotate the bytes
crc_calc = ((crc_calc >> 8) & 0x00FF00FF) | ((crc_calc << 8) & 0xFF00FF00)
return f"0x{crc_calc:08X}"
def get_user_input():
"""
Prompts the user for NTAG UID and NFC second string, validates the input,
and returns the parsed UID and NFC second string.
Returns:
A tuple containing the UID as a list of integers and the NFC second
string as a bytes object.
"""
while True:
uid_str = input("Enter the NTAG UID in the format '04:EC:FC:A2:94:10:90': ")
nfc_second_str = input("Enter the Head MFG String (e.g., '221214 12K'): ")
try:
uid = [int(x, 16) for x in uid_str.split(':')]
if len(uid) != 7:
raise ValueError("The UID must have 7 bytes.")
nfc_second = nfc_second_str.encode("utf-8")
return uid, nfc_second
except ValueError as e:
print(f"Invalid input: {e}. Please try again.")
--- Main execution ---
if name == "main":
parser = argparse.ArgumentParser(description="Compute Philips Sonicare NFC password.")
parser.add_argument("--uid", help="NTAG UID in the format '04:EC:FC:A2:94:10:90'")
parser.add_argument("--mfg", help="Head MFG String (e.g., '221214 12K')")
args = parser.parse_args()
if args.uid and args.mfg:
try:
uid = [int(x, 16) for x in args.uid.split(':')]
if len(uid) != 7:
raise ValueError("The UID must have 7 bytes.")
nfc_second = args.mfg.encode("utf-8")
except ValueError as e:
print(f"Invalid input: {e}")
exit(1)
else:
uid, nfc_second = get_user_input()
# Calculate the actual CRC value
crc_actual = compute_password(uid, nfc_second)
# Print the results
print(f"\nby @ATC1441 NFC CRC : {crc_actual}")
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just for fun - Zig version 🤓⚡