1616from schnee .adapters .ntag .crypt import aes_decrypt , aes_encrypt , xor_bytes
1717from schnee .adapters .ntag .utils import (
1818 Offset ,
19+ build_ndef_url_file_data ,
1920 calculate_offsets ,
2021 int_to_3bytes_le ,
21- wrap_ndef_record ,
2222)
2323from schnee .utils .logger import get_logger
2424
@@ -534,20 +534,47 @@ def _change_key_iv(
534534 plain_data = iv_input ,
535535 )
536536
537- def configure_sdm_url (self , url : str , * , cmd_ctr : int = 1 ) -> None :
537+ def configure_sdm_url (self , url : str , * , cmd_ctr : int = 0 ) -> None :
538538 """Authenticate, write an NDEF URL, and enable SDM explicitly."""
539+ self .write_ndef_url_with_auth (url )
540+ self .set_sdm_enabled (enabled = True , url_template = url , cmd_ctr = cmd_ctr )
541+
542+ def write_ndef_url_with_auth (self , url : str ) -> None :
543+ """Authenticate and write an NDEF URL to the NTAG 424 DNA NDEF file."""
544+ self .connect ()
545+ self .authenticate ()
546+ self .write_ndef_url (url_string = url )
547+
548+ def set_sdm_enabled (
549+ self ,
550+ * ,
551+ enabled : bool ,
552+ url_template : str | None = None ,
553+ cmd_ctr : int = 0 ,
554+ ) -> None :
555+ """Authenticate and enable or disable SDM for the NDEF file."""
539556 self .connect ()
540557 k_ses_auth_enc , k_ses_auth_mac , ti , _iv = self .authenticate ()
541- self .write_ndef_url (
542- url_string = url ,
543- )
544- offset = calculate_offsets (url )
545- self ._enable_sdm (
558+ if enabled :
559+ if url_template is None :
560+ msg = "url_template is required when enabling SDM"
561+ raise ValueError (msg )
562+ offset = calculate_offsets (url_template )
563+ self ._change_sdm_settings (
564+ session_key_enc = k_ses_auth_enc ,
565+ session_key_mac = k_ses_auth_mac ,
566+ ti = ti ,
567+ cmd_ctr = cmd_ctr ,
568+ payload = self ._build_enable_sdm_payload (offset ),
569+ )
570+ return
571+
572+ self ._change_sdm_settings (
546573 session_key_enc = k_ses_auth_enc ,
547574 session_key_mac = k_ses_auth_mac ,
548575 ti = ti ,
549576 cmd_ctr = cmd_ctr ,
550- offset = offset ,
577+ payload = self . _build_disable_sdm_payload () ,
551578 )
552579
553580 def _apdu_select (self ) -> None :
@@ -562,17 +589,12 @@ def write_ndef_url(
562589 """Write NDEF URL to Tag"""
563590 _logger .debug ("--- Write NDEF Data (URL) ---" )
564591
565- # 1. URLをNDEFデータに変換
566- ndef_record = wrap_ndef_record (url_string )
567- # ファイル全体のデータ: [Length(2bytes)] + [NDEF Record]
568- file_data = [len (ndef_record ) >> 8 & 255 , len (ndef_record ) & 255 , * ndef_record ]
569-
570592 _logger .debug ("Writing URL: %s" , url_string )
571593 response = self .connection .send_apdu (
572594 Ntag424ApduPreset .write_data_file (
573595 file_no = Ntag424ApduPreset .ndef_file_no ,
574596 offset = [0x00 , 0x00 , 0x00 ],
575- data = file_data ,
597+ data = build_ndef_url_file_data ( url_string ) ,
576598 ),
577599 )
578600 _logger .debug ("Response: %s" , toHexString (response .data ))
@@ -639,29 +661,47 @@ def aes_cbc_encrypt_for_ev2(
639661 # 3. 暗号化実行
640662 return cipher .encrypt (padded_data )
641663
642- def _enable_sdm (
664+ @staticmethod
665+ def _build_enable_sdm_payload (offset : Offset ) -> list [int ]:
666+ """Build ChangeFileSettings plaintext payload that enables SDM."""
667+ file_option = 0x40
668+ access_rights = [0x00 , 0xE0 ]
669+ sdm_options = 0xC1
670+ sdm_access_rights = [0xF1 , 0xE1 ]
671+
672+ return [
673+ file_option ,
674+ * access_rights ,
675+ sdm_options ,
676+ * sdm_access_rights ,
677+ * int_to_3bytes_le (offset .uid_offset ),
678+ * int_to_3bytes_le (offset .counter_offset ),
679+ * int_to_3bytes_le (offset .mac_input_offset ),
680+ * int_to_3bytes_le (offset .mac_offset ),
681+ ]
682+
683+ @staticmethod
684+ def _build_disable_sdm_payload () -> list [int ]:
685+ """Build ChangeFileSettings plaintext payload that disables SDM."""
686+ file_option = 0x00
687+ access_rights = [0x00 , 0xE0 ]
688+ return [file_option , * access_rights ]
689+
690+ def _change_sdm_settings (
643691 self ,
644692 session_key_enc : bytes ,
645693 session_key_mac : bytes ,
646694 ti : bytes ,
647695 cmd_ctr : int ,
648- offset : Offset ,
696+ payload : list [ int ] ,
649697 ) -> None :
650- """Disable SDM (ChangeFileSettings)"""
651- _logger .debug ("--- Phase 3: ChangeFileSettings (Disable SDM) ---" )
698+ """Send a protected ChangeFileSettings command for the NDEF file."""
699+ _logger .debug ("--- ChangeFileSettings (SDM) ---" )
700+ if not 0 <= cmd_ctr <= COMMAND_COUNTER_MAX :
701+ msg = "cmd_ctr must be between 0 and 65535"
702+ raise ValueError (msg )
652703
653- # 設定値
654704 file_no = 0x02
655- file_option = 0x40 # SDM OFF (Plain Communication)
656- access_rights = [0x00 , 0xE0 ] # Read=Free, Write=Key0 (現在の値を維持)
657- sdm_options = 0xC1
658- sdm_access_rights = [0xF1 , 0x21 ]
659-
660- # ペイロード組み立て
661- payload = [file_option , * access_rights , sdm_options , * sdm_access_rights ]
662- payload += int_to_3bytes_le (offset .uid_offset ) # 33. UID
663- payload += int_to_3bytes_le (offset .mac_offset ) # 7. MacIn
664- payload += int_to_3bytes_le (offset .mac_offset ) # 59. MacOut
665705
666706 iv = [
667707 0xA5 ,
0 commit comments