Unlike most of my technology articles, which I write myself and then refine with an LLM, this article was largely written by an LLM. I used an LLM to find a solution, checked that it worked, and then organised the LLM’s response into this article.
The procedure was tested on my CanoKey Canary with firmware 3.0.3-0-g30917b92.
1. Prepare the required tools
On Debian or Ubuntu:
$ sudo apt install python3-usb libusb-1.0-0
Then use this script to send commands:
#!/usr/bin/env python3
import time
import usb.core
import usb.util
VID = 0x20A0
PID = 0x42D4
INTERFACE = 1
def apdu(device: usb.core.Device, command: str) -> bytes:
data = bytes.fromhex(command)
# Send command APDU.
device.ctrl_transfer(
0x41, # Host-to-device | Vendor | Interface
0x00, # CMD
0x0000,
INTERFACE,
data,
)
# Wait for execution to finish.
while True:
status = device.ctrl_transfer(
0xC1, # Device-to-host | Vendor | Interface
0x02, # STAT
0x0000,
INTERFACE,
1,
)
if bytes(status)[0] == 0x00:
break
time.sleep(0.05)
# Retrieve response APDU.
response = device.ctrl_transfer(
0xC1,
0x01, # RESP
0x0000,
INTERFACE,
1500,
)
return bytes(response)
def main() -> None:
device = usb.core.find(idVendor=VID, idProduct=PID)
if device is None:
raise SystemExit("CanoKey 20A0:42D4 not found")
print(f"Found {VID:04X}:{PID:04X}")
while True:
command = input("> ")
if command == "":
break
response = apdu(device, command)
print(f"< {response.hex(' ').upper()}")
if __name__ == "__main__":
main()
2. Select the Admin applet
The Admin applet’s application identifier (AID) is F000000000. Send:
00 A4 04 00 05 F0 00 00 00 00
Expected response:
90 00
This means the Admin applet was selected successfully.
3. Exhaust the Admin PIN retry counter
This step is required by the documented factory-reset procedure when you cannot authenticate for a normal reset.
First, check the counter with:
00 20 00 00
The initial response should be:
63 C3
This indicates that three retries remain.
Send the following APDU with a deliberately incorrect PIN three times:
00 20 00 00 06 30 30 30 30 30 30
The PIN bytes represent 000000. The expected responses are:
63 C2(Two retries remain)63 C1(One retry remains)69 83(PIN is blocked)
Important: Do not exhaust the retries if you still need to use the existing PIN normally. In this procedure, deliberately blocking the PIN enables the locked-out factory-reset route.
4. Send the factory-reset command
Use the WebUSB script again and select the Admin applet before sending the reset APDU:
00 A4 04 00 05 F0 00 00 00 00
00 50 00 00 05 52 45 53 45 54
The second APDU is the factory-reset command:
00 50 00 00 05 RESET
Here, RESET is the five-byte ASCII string 52 45 53 45 54. CanoKey specifies this instruction as INS=50; the Admin PIN must already be blocked.
5. Follow the LED prompts
When you send the command, the CanoKey begins blinking.
- Touch the key promptly when it blinks.
- Continue touching it in response to the successive fast and slow blinking sequences.
- Keep the key connected and allow your Python script to continue polling.
- Wait until the script returns the final response:
90 00
The final 90 00 confirms that the operation succeeded. Your device returns it after the repeated touch sequence.
The complete sequence at a glance
Select the Admin applet
00 A4 04 00 05 F0 00 00 00 00
Block the Admin PIN
Send 00 20 00 00 06 30 30 30 30 30 30 three times.
Start the factory reset
00 50 00 00 05 52 45 53 45 54
Touch until the reset is complete
Respond to every requested blink until the result is 90 00.