Andrey Kurennykh
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    /\*<!\[CDATA\[\*/ div.rbtoc1613655572899 {padding: 0px;} div.rbtoc1613655572899 ul {list-style: none;margin-left: 0px;} div.rbtoc1613655572899 li {margin-left: 0px;padding-left: 0px;} /\*\]\]>\*/ * [Technical manual](#CardSpecv3-Technicalmanual) * [1\. About Tangem cards](#CardSpecv3-1.AboutTangemcards) * [2\. Life cycle](#CardSpecv3-2.Lifecycle) * [3\. Security](#CardSpecv3-3.Security) * [3.1 General](#CardSpecv3-3.1General) * [3.2 Card attestation](#CardSpecv3-3.2Cardattestation) * [3.3 Issuers](#CardSpecv3-3.3Issuers) * [3.3.1 Issuer transaction key](#CardSpecv3-3.3.1Issuertransactionkey) * [3.3.2 Issuer data key](#CardSpecv3-3.3.2Issuerdatakey) * [3.5 Wallet key](#CardSpecv3-3.5Walletkey) * [3.6 User’s codes](#CardSpecv3-3.6User’scodes) * [3.6.1 PIN1 code](#CardSpecv3-3.6.1PIN1code) * [3.6.2 PIN2 code](#CardSpecv3-3.6.2PIN2code) * [3.6.3 PIN3 code](#CardSpecv3-3.6.3PIN3code) * [3.6.4 CVC code](#CardSpecv3-3.6.4CVCcode) * [3.7 Linked terminal](#CardSpecv3-3.7Linkedterminal) * [3.8 Security Delay](#CardSpecv3-3.8SecurityDelay) * [4\. NFC communication](#CardSpecv3-4.NFCcommunication) * [4.1 General](#CardSpecv3-4.1General) * [4.2 TLV format (SimpleTLV)](#CardSpecv3-4.2TLVformat(SimpleTLV)) * [4.3 Non-encrypted request](#CardSpecv3-4.3Non-encryptedrequest) * [4.4 Fast encrypted request](#CardSpecv3-4.4Fastencryptedrequest) * [4.5 Strong encrypted request](#CardSpecv3-4.5Strongencryptedrequest) * [4.6 OPEN\_SESSION command](#CardSpecv3-4.6OPEN_SESSIONcommand) * [4.6.1 Fast Encryption](#CardSpecv3-4.6.1FastEncryption) * [4.6.2 Strong Encryption](#CardSpecv3-4.6.2StrongEncryption) * [4.7 Pending security delay](#CardSpecv3-4.7Pendingsecuritydelay) * [5\. Personalization](#CardSpecv3-5.Personalization) * [5.1 UID and CID](#CardSpecv3-5.1UIDandCID) * [5.2 NDEF records](#CardSpecv3-5.2NDEFrecords) * [5.3 Card\_Data](#CardSpecv3-5.3Card_Data) * [6\. Dynamic NDEF](#CardSpecv3-6.DynamicNDEF) * [7\. Activation](#CardSpecv3-7.Activation) * [8\. Commands](#CardSpecv3-8.Commands) * [8.1 ACTIVATE\_CARD](#CardSpecv3-8.1ACTIVATE_CARD) * [8.2 READ\_CARD](#CardSpecv3-8.2READ_CARD) * [8.3 CREATE\_WALLET](#CardSpecv3-8.3CREATE_WALLET) * [8.4 CHECK\_WALLET](#CardSpecv3-8.4CHECK_WALLET) * [8.5 SET\_PIN](#CardSpecv3-8.5SET_PIN) * [8.6 SIGN](#CardSpecv3-8.6SIGN) * [8.6.1 Wallet Mode](#CardSpecv3-8.6.1WalletMode) * [8.6.2 POS mode](#CardSpecv3-8.6.2POSmode) * [8.7 READ\_ISSUER\_DATA](#CardSpecv3-8.7READ_ISSUER_DATA) * [8.7.1 Read issuer extra data](#CardSpecv3-8.7.1Readissuerextradata) * [8.8 WRITE\_ISSUER\_DATA](#CardSpecv3-8.8WRITE_ISSUER_DATA) * [8.8.1 Write issuer extra data](#CardSpecv3-8.8.1Writeissuerextradata) * [8.9 VERIFY\_CODE](#CardSpecv3-8.9VERIFY_CODE) * [8.10 VERIFY\_CARD](#CardSpecv3-8.10VERIFY_CARD) * [8.11 VALIDATE\_CARD](#CardSpecv3-8.11VALIDATE_CARD) * [8.12 PURGE\_WALLET](#CardSpecv3-8.12PURGE_WALLET) * [8.13 READ\_USER\_DATA](#CardSpecv3-8.13READ_USER_DATA) * [8.14 WRITE\_USER\_DATA](#CardSpecv3-8.14WRITE_USER_DATA) * [9 Appendix A – Dynamic NDEF](#CardSpecv3-9AppendixA–DynamicNDEF) * [9.1 General description](#CardSpecv3-9.1Generaldescription) * [9.2 Example (card with PIN set):](#CardSpecv3-9.2Example(cardwithPINset):) * [9.3 Example (before wallet creation):](#CardSpecv3-9.3Example(beforewalletcreation):) * [9.4 Example (after wallet creation):](#CardSpecv3-9.4Example(afterwalletcreation):) * [10\. Appendix B – CRC-A](#CardSpecv3-10.AppendixB–CRC-A) * [11\. Appendix C – Verification of Luhn code](#CardSpecv3-11.AppendixC–VerificationofLuhncode) * [12\. Appendix D - Examples](#CardSpecv3-12.AppendixD-Examples) * [12.1 Read command](#CardSpecv3-12.1Readcommand) Technical manual ================ 1\. About Tangem cards ---------------------- The Tangem card is a self-custodial hardware wallet for blockchain assets. The main functions of Tangem cards are to securely create and store a private key from a blockchain wallet and sign blockchain transactions. Tangem card does not allow users to import/export, backup/restore private keys, in this way guarantying that the wallet is unique and unclonable. Above this, the cards provide mechanisms to implement two-factor authentication of transactions, off-line validation of wallet balance, protection against counterfeit and cloning, secure signing of transactions on POS devices, and more. All these capabilities are described in this document. The cards carry an EAL6+ certified secure smart-card chip based on ARM SC000 core architecture and having ISO14443 Type A contactless interface. Tangem’s card firmware is a native card OS (**_COS_**) providing operations with a blockchain wallet and a proprietary communication protocol on top of ISO14443 to interact with a contactless terminal (_host_). Once loaded into a particular card, COS binary code cannot be updated or managed. The host application (**_App_**), which is almost always installed on an NFC smartphone, provides UI and interaction with the card via Android or iOS NFC interface. Tangem NFC protocol is not compatible will older Android smartphones having NFC modules that do not support long (> 261 bytes) APDUs. Due to the fact that old iOS versions support only read-only NDEFs, functionality on old iOS is limited to the reading of the card and non-strict balance validation by using a mechanism described in section Dynamic NDEF. Beginning from iOS 13, all NFC-enabled iPhone devices support all features of the Tangem NFC protocol. Main functions of the host are to (1) obtain wallet public key (address) from the card, (2) verify that the card possesses corresponding private key through a challenge-response mechanism, (3) obtain wallet balance from external blockchain nodes, (4) attest the card. Tangem develops the “TANGEM” mobile application for Android OS and iOS which implements all these functions. The full source code of Tangem’s host app implementing all functions described in this document will be available on GitHub. Third-party developers are welcome to integrate Tangem NFC protocol into their applications using detailed and convenient SDK for Android and iOS: [https://github.com/Tangem/tangem-sdk-android](https://github.com/Tangem/tangem-sdk-android) [https://github.com/Tangem/tangem-sdk-ios](https://slack-redir.net/link?url=https%3A%2F%2Fgithub.com%2FTangem%2Ftangem-sdk-ios) Tangem does not develop or provide any server back-end for validation of the wallet balance. The system fully relies on the existing decentralized infrastructure of blockchain nodes with open external API. Tangem cards are self-sufficient, and the circulation of cards is uncontrolled. The only role of Tangem in the ecosystem is to sustain the card attestation chain ensuring the authenticity of the cards and integrity of COS. 2\. Life cycle -------------- In the initial state, right after the COS is loaded, the card’s Status is set to ‘New’. In this status, the card will only accept PERSONALIZE command from the host. This command can be executed only once to define the principal parameters of the card. Host must pass all parameters AES256-encrypted with Personalization\_Key in one request payload. Once the command is executed, these parameters become read-only, and the card is rendered to the initial state of the main cycle with Status set to ‘Empty’. At this moment, the card is ready for operation by the end-user and contains all data except for the blockchain wallet keys. App must request COS to generate a wallet key pair by calling CREATE\_WALLET command. This command will render the card to ‘Loaded’ state and return wallet’s public key to the user, who can top up the newly created wallet in the blockchain using any third-party wallet app. In a default configuration, COS is not aware of incoming transactions and wallet balance, although COS provides two optional mechanisms to store trusted balance on-card and enable offline balance verification (described below). COS in ‘Loaded’ state supports all commands, including SIGN. Calling SIGN command will make COS generate and return a transaction signature. If the card depletes the number of allowed signatures defined during personalization, or if the user opts to delete the wallet by calling PURGE\_WALLET command, COS will destroy all wallet data and switch either to ‘Purged’ state, or back to ‘Empty’ state, depending on the reusability option that is also defined during personalization. ‘Purged’ state is final, it makes the card useless. 3\. Security ------------ ### 3.1 General Tangem card guarantees that it is the only place in the world that holds the private key of the blockchain wallet (address). Therefore, it is not possible to export, import, backup, restore, derive or in some other way gain access to the wallet private key. Loss or physical destruction of the card is equivalent to loss of the wallet’s funds. Tangem cards pass rigorous testing and can withstand environmental extremes and occasional mechanical deformation within limits defined in ISO7810 standard. It is recommended to avoid intentional bending with force and exposure to temperatures above 80C, powerful X-rays and magnetic field (e.g. MRI). The cards’ microprocessor employs many anti-tampering mechanisms that can recognize various types of attacks. Tangem COS will react to attempts of such attacks according to its severity. In some situations, the card will permanently erase all wallet data in order to prevent unauthorized access to the private key. Cards will also withstand unpredicted power outage that may occur when NFC field or the host device is removed from the card. On-card data integrity is protected by a proprietary anti-tearing mechanism and triple storage redundancy. Embedded non-volatile memory (NVM) is certified and tested for 20 years of the data retention period. ### 3.2 Card attestation In the process of manufacturing, every new Tangem card internally generates a Card Key pair _Card\_PublicKey / Card\_PrivateKey_. The private key _Card\_PrivateKey_ is permanently stored in the card memory and is not accessible to external applications via NFC interface. At the same time, Tangem publishes the list of _CID_ and corresponding _Card\_PublicKey_ values in its card attestation service and/or hands over this list to the card Issuer. To attest the card, app should: 1. call READ\_CARD command to obtain CID and Card\_PublicKey 2. call VERIFY\_CARD command to ensure the card has not been counterfeited: by using the standard challenge-response scheme, the card proves possession of Card\_PrivateKey that corresponds to Card\_PublicKey returned by READ\_CARD command, 3. ensure that the card’s _CID_ presents and corresponds to _Card\_PublicKey_ in published Tangem’s card list, through either Tangem attestation service or Issuer’s own service, 4. optionally, in offline, verify _Manufacturer\_Signature_ using non-secret _Manufacturer\_PublicKey_ stored in the app. ### 3.3 Issuers Issuer is a third-party team or company wishing to use Tangem cards in their project or business. Issuers would have their own distribution channel and can tailor Tangem solution to their needs: * to choose a type of blockchain assets Tangem card carries (e.g. ERC20 tokens), * to integrate Tangem cards into own mobile host application connected to issuer’s own server back-end or some third-party nodes/services, * to order customized cards from Tangem: it could be a new graphic design and personalization parameters that depend on the issuer’s use-case and security model. In this scenario, Tangem cannot be accountable to end-users for the issuer’s product and funds stored on the cards. Tangem will remain responsible only for the card’s security and card attestation process. #### 3.3.1 Issuer transaction key Tangem cards support the optional security mechanism allowing the issuer to authorize transactions before they are signed by the user. In case the issuer opts to utilize this mechanism, the issuer has to generate Issuer Transaction Key pair _Issuer\_Transaction\_PublicKey / Issuer\_Transaction\_PrivateKey_ either for each card or for the whole batch. The private key _Issuer\_Transaction\_PrivateKey_ is permanently stored in a secure back-end of the issuer (e.g. HSM). The public key _Issuer\_Transaction\_PublicKey_ is securely written into the Tangem card during personalization by Tangem and will be permanently stored there throughout the whole card life cycle, with no access by host application via NFC interface. App shall call READ\_CARD command to get _Signing\_Method_ parameter that defines what data should be submitted to SIGN command. If _Signing\_Method_ is ‘2’, ‘3’, ‘4’, or ‘5’, then the card will sign only those data previously signed by the issuer. App has to obtain issuer’s signature of the data from the issuer’s own back-end services before submitting it to SIGN command. This mechanism enables two-factor authentication of transactions by using external issuer services. #### 3.3.2 Issuer data key Issuer may also use a special 512-byte memory block _Issuer\_Data_ to securely store and update information in COS. For example, this mechanism could be employed for enabling off-line validation of the wallet balance and attesting of cards by the issuer (in addition to Tangem’s attestation). The issuer should define the purpose of use, payload, and format of _Issuer\_Data_ field. Note that _Issuer\_Data_ is never changed or parsed by the executable code the Tangem COS. The issuer has to generate single Issuer Data Key pair _Issuer\_Data\_PublicKey_ / _Issuer\_Data\_PrivateKey_, same for all issuer’s cards. The private key _Issuer\_Data\_PrivateKey_ is permanently stored in a secure back-end of the issuer (e.g. HSM). The non-secret public key _Issuer\_Data\_PublicKey_ is stored both in COS (during personalization) and issuer’s host application that will use it to validate _Issuer\_Data_ field received from READ\_ISSUER\_DATA command. In case the issuer opts to utilize _Issuer\_Data_ field, there are two options: 1. _Issuer\_Data_ is written into COS by host application by using WRITE\_ISSUER\_DATA command. This option works only if Signing\_Method is set is ‘0’, ‘1’, ‘2’, or ‘3’. _Issuer\_Data_ can be either permanent and defined during personalization, or updatable during the life cycle. Updating of _Issuer\_Data_ should not be bound to a specific transaction and should tolerate unpredictable delays caused by the end-user not tapping the card for a long period of time. The issuer’s host application should obtain the signature _Issuer\_Data\_Signature_ of _Issuer\_Data_ from issuer’s own back-end services. This is not a part of the solution provided by Tangem team. 2. _Issuer\_Data_ is updated strictly during the execution of SIGN command. This option works only if Signing\_Method is set to ‘4’ or ‘5’. For this option, WRITE\_ISSUER\_DATA will not work and will return error with status word SW\_ERROR\_PROCESSING\_COMMAND = 0x6286 **Version 2.30 and later.** Issuer may also use extended 32kB memory block _Issuer\_Extra\_Data_ to securely store and update information within the card. For example, this mechanism could be employed for storing personal biometric data on ID cards. This memory can be marked as “write once” by specifying _RestrictOverwriteIssuerDataEx_ flag in _SettingsMask_. ### 3.5 Wallet key App shall call CREATE\_WALLET command to turn an empty Tangem card into a ‘cold’ blockchain wallet ready for top-up. This command will generate a wallet key pair _Wallet\_PublicKey / Wallet\_PrivateKey_. The private key _Wallet\_PrivateKey_ is the main secret of the card. It is never revealed and accessible by host application via NFC interface. COS will internally use _Wallet\_PrivateKey_ only during execution of SIGN and CHECK\_WALLET commands. App will need to obtain _Wallet\_PublicKey_ from the response of CREATE\_WALLET or READ\_CARD commands and then transform it into an address of corresponding blockchain wallet according to a specific blockchain algorithm. Calling of PURGE\_WALLET command will permanently delete the wallet key pair. If the card was personalized as reusable (see _Is\_Reusable_ flag in _Settings\_Mask_) then App may call CREATE\_WALLET command to generate a new wallet key pair. ### 3.6 User’s codes COS provides three codes to protect the card: PIN1, PIN2, CVC. The application should submit one, two, or all of these codes in command parameters in order to be authorized by COS. The scheme of protection and personalization should be defined by the issuer as follows: * what codes are required, * how codes are used or changed by end-users, * how codes are delivered to end-users, * initial values of the codes set during personalization. The card protects itself against brute force snigging of PIN1, PIN2, CVC codes. After each invalid code is submitted, COS gradually increases the delay of response to all further commands until the correct code is submitted. Therefore, the card will never block itself regardless of the number of invalid inputs. However, when the correct code if submitted after a few invalid codes, the user will have to await card’s response for the amount of time proportional to the number of prior invalid inputs. The response delay will be set to zero only after the card receives the correct code. **Version 1.19 and later.** The delay of PIN1 response will not increase in case NFC encryption is disabled and host submits default PIN1. PIN2 response delay will also not increase when host submits default PIN2. It this way, the host can verify that the card has default PIN values without future delay penalty. #### 3.6.1 PIN1 code This 32-byte code restricts access to the whole card. App must submit the correct value of PIN1 in each command, including READ\_CARD (at the moment, when CID is not yet known to the app). By default, all cards have PIN1 set to SHA256(‘000000’), so that every host application on any NFC smartphone could obtain card and wallet data. The end-user might optionally restrict access to the whole card and all commands by setting a user’s PIN1 code. Issuer can disable changing PIN1 by defining a special parameter during personalization (see _Allow\_SET\_PIN1_ flag in _Settings\_Mask_). A non-default PIN1 is required for remote card activation (in this case PIN1 is used as a card activation key). If the card is used as a hardware wallet for storing high-value assets, it is also recommended to require the end-user to set a non-default PIN1 at least eight characters long. For additional security purposes, COS stores all wallet data, including _Wallet\_PrivateKey_, in NVM encrypted with AES256 key derived from PIN1. #### 3.6.2 PIN2 code All cards will require submitting the correct 32-byte PIN2 code in order to sign a transaction or to perform other commands entailing a change of the card state. App should ask the user to enter PIN2 before sending such commands to the card. The main purpose of using PIN2 is to protect against proximity attack, during which an attacker tries to discreetly scan / detect Tangem cards with default PIN1 in proximity and withdraw assets from such cards by signing a transaction. Issuer can disable changing PIN2 by defining a special parameter during personalization (_Allow\_SET\_PIN2_ flag in _Settings\_Mask_). The recommended minimum length of user’s PIN2 is six characters. By default, all cards have PIN2 set to SHA256(‘000’). Default PIN2 should not be used if _CVC_ and _Pause\_Before\_PIN2_ are not used. If the card is being handed over between from one holder to another, PIN2 should be temporarily set to a default value SHA256(‘000’), so that the receiving holder could validate and change PIN1 and PIN2 codes by calling SET\_PIN command. Once the new hold has the card in possession, he/she should immediately set own secret PIN2. #### 3.6.4 CVC code Issuer can require using a CVC code with non-transferrable cards (e.g. a personal reusable cold wallet or one-off card). CVC code will be loaded into COS and printed on the card during personalization by Tangem. CVC value is fixed during the whole card life cycle. If it is set, the card will require submitting correct CVC code in order to sign a transaction or to perform other commands entailing a change of the card state. App should verify if CVC is enabled (_Use\_CVC_ flag in _Settings\_Mask_) and then ask the user to enter CVC before sending such commands to the card. The purpose of using CVC is the same as for PIN2 – to protect the card against ‘drive by’ attack. However, it allows keeping it more simple for the user. If PIN1 and PIN2 always stay default and never asked in application UI, the user needs only to read and enter CVC printed on the card. ### 3.7 Linked terminal **Version 2.30 and later.** App can optionally generate ECDSA key pair _Terminal\_PrivateKey / Terminal\_PublicKey._ And then submit _Terminal\_PublicKey_ to the card in any SIGN command. Once SIGN is successfully executed by COS, including PIN2 verification and/or completion of security delay, the submitted _Terminal\_PublicKey_ key is stored by COS. After that, the App instance is deemed trusted by COS and COS will allow skipping security delay for subsequent SIGN operations thus improving convenience without sacrificing security. In order to skip security delay, App should use _Terminal\_PrivateKey_ to compute the signature of the data being submitted to SIGN command for signing and transmit this signature in _Terminal\_Transaction\_Signature_ parameter in the same SIGN command. COS will verify the correctness of _Terminal\_Transaction\_Signature_ using previously_\-_stored _Terminal\_PublicKey_ and, if correct, will skip security delay for the current SIGN operation. This behavior can be enabled by setting flag _Skip\_Security\_Delay\_If\_Validated\_By\_Linked\_Terminal_ in _Security\_Mask_. ### 3.8 Security Delay COS provides a special mechanism to protect against proximity attack on a card with default or very weak PIN1 and PIN2. For that, COS can enforce a “security delay” up to 60 seconds long between reception and execution of a command. During the delay, the card shall be kept within NFC field of the terminal and NFC session shall be active until the delay countdown is finished on the card. See details in section “Pending security delay”. There are a few flags in _Setting\_Mask_ field to control security delay behavior: * _Pause\_Before\_PIN2_ enforces and defines the amount of the delay before COS executes any of the commands protected by PIN2. It is recommended to apply at least 10 seconds delay if the card assumes using the default PIN2. Pause\_Before\_PIN2 is defined during personalization. * _Smart\_Security\_Delay_ flag in _Settings\_Mask_ will make COS automatically disable the security delay if non-default PIN2 is set on the card. **Version 2.05 and later** * _Skip\_Security\_Delay\_If\_Validated\_By\_Issuer_ will skip security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5). **Version 2.30 and later** * _Skip\_Security\_Delay\_If\_Validated\_By\_Linked\_Terminal_ will skip security delay in SIGN command if the transaction was signed by linked terminal (for signing methods 0, 1). 4\. NFC communication --------------------- ### 4.1 General Tangem NFC protocol is based on ISO14443-3 layer, but do not fully comply with ISO14443-4. It has a proprietary set of features tailored to blockchain usage. The protocol contains only atomic commands, meaning that every command makes some complete action, and either is fully executed or fully rolls back to the previous card state. App should obtain 4-byte card UID code when initially establishing communication via ISO14443-3 stack. Standard ISO7816-4 format is used for all requests: \[CLA, INS, P1, P2, Lc, Payload\]. Maximum length of command is limited to 1024 bytes. COS supports three options of communication: 1\. Plain data packets with non-encrypted Payload: This option is not recommended for large-scale commercial projects, because it potentially exposes the card to eavesdropping and replay attacks. 2\. Fast symmetric encryption with mutual challenges: **Version 1.16 and later.** If non-default PIN1 is set, the communication is encrypted by AES256 and safely protected against man-in-the-middle and replay attacks. Packets could be potentially eavesdropped and decrypted later by brute-forcing weaker PIN1 codes. However, this attack has little practical meaning. Fast encryption is optimal for most use cases. 3\. Strong encryption with ECDH shared secret (elliptic curve Diffie-Hellman): Communication is encrypted by AES256 and fully protected against eavesdropping, man-in-the-middle and replay attacks. The downside is 2x lower performance and longer card’s reaction time. Every Tangem card supports strong encryption mode. Issuer can opt to enable fast encryption and non-encrypted mode during personalization. App can choose desirable encryption mode among those supported by the card by setting the corresponding P2 parameter in a command request as described below. If the card does not support chosen encryption mode, it will respond with error status word SW\_NEED\_ENCRYPTION = 0x6982. ### 4.2 TLV format (SimpleTLV) TLV structure is a list of triples <Tag, Length, Value>, where: * Tag - 1 byte - field ID, * Length - 1 or 3 bytes - value length, * Value - \[Length\] byes - field value. ``` TLV1 TAG1: 1 byte Length1: 1 byte (length 1-255) or 3 bytes with extended coding [0xFF, high, low] Value1: [Length1 bytes] TLV2 ... TLVm ``` Field value format: * The most significant byte value is at the lowest address (Big-endian) * Strings can be null-terminated in utf-8 encoding * Public key - as uncompressed ( 0x04, X\[32\], Y\[32\] ) for ‘secp256k1’ curve or as compressed X\[32\] for ‘ed25519’ curve * Signature - as ( R\[32\], S\[32\] ) ### 4.3 Non-encrypted request Tangem COS non-encrypted requests: * CLA, P1, P2 = 0x00 * INS – command code 1 byte (e.g. READ\_CARD = 0xF2, see Commands section) * Lс – length of Payload 1 byte (length 1-255) or 3 bytes with extended coding \[0x00, high, low\] * Payload – command parameters in TLV format Tangem COS non-encrypted response: * Response\_Data – command response in TLV format * Status\_Word – command result (2 bytes, bigendian) Status words used: | | | | --- | --- | | **Status** | **Bytes** | | SW\_PROCESS\_COMPLETED | 0x9000 | | SW\_NEED\_ENCRYPTION | 0x6982 | | SW\_INVALID\_PARAMS | 0x6A86 | | SW\_ERROR\_PROCESSING\_COMMAND | 0x6286 | | SW\_INVALID\_STATE | 0x6985 | | SW\_PINS\_NOT\_CHANGED | 0x9000 | | SW\_PIN1\_CHANGED | 0x9001 | | SW\_PIN2\_CHANGED | 0x9002 | | SW\_PINS\_CHANGED | 0x9003 | Version 2.30 and later. | | | | --- | --- | | SW\_PIN3\_CHANGED | 0x9004 | | SW\_PINS\_CHANGED | 0x900X, X – changed PINs mask (0x01-PIN1, 0x02-PIN2, 0x04-PIN3) | | SW\_EXT\_SIGN\_BLOCKED | 0x6983 | Data types and structures: String values have maximum size of 16 bytes, 0x00 is the end symbol Public key – 65 bytes, elliptic curve point P(X,Y) in uncompressed format byte\[0\]=0x04 byte\[1..32\] - X coordinate, byte\[32..64\] - Y coordinate Signature – 64 bytes \[R\[32\],S\[32\]\] ### 4.4 Fast encrypted request Tangem COS fast encrypted request: * CLA, P1 = 0x01, P2 = 0x00 * INS – command code - 1 byte * Lс – length of Payload - 1 byte (length 1-255) or 3 bytes with extended coding \[0x00, high, low\] * Payload: 1) Prepare tlv\_data array by concatenating: \- Length of TLV data (as per non-encrypted request format, see above) - 2 bytes \- CRC16 of TLV data - 2 bytes \- TLV data 2) Generate random 16-byte array \[challengeA\] in App, call OPEN\_SESSION command with P2 = 0x01 and challengeA as a parameter, 3) COS will generate and return random 16-byte array \[challengeB\] as a response to OPEN\_SESSION command, 4) calculate protocol\_key = PBKDF2(SHA256(PIN1), UID, 50), where UID - ISO 14443-3 unique identifier, 5) calculate session\_key = SHA256(challengeA | challengeB | protocol\_key), 6) Payload = AES256(session\_key, tlv\_data). Tangem COS fast encrypted response: * Response\_Data – contains concatenated: \- Length of response TLV data - 2 bytes \- CRC16 of response TLV data - 2 bytes \- AES256( session\_key , response\_tlv\_data) * Status\_Word – command result (2 bytes, big-endian) CRC16 of TLV data should always be verified both by App and COS to exclude dealing with corrupted or tampered data. CRC16 in Tangem means CRC-A implementation of ISO 14443-3. See Java sample code in the Appendix B. ### 4.5 Strong encrypted request **Tangem COS strong encrypted request:** * CLA, P1 = 0x02, P2 = 0x00 * INS – command code - 1 byte * Lс – length of Payload - 1 byte (length 1-255) or 3 bytes with extended coding \[0x00, high, low\] * Payload – 1) Prepare tlv\_data array by concatenating: \- Length of TLV data (as per non-encrypted request format, see above) - 2 bytes \- CRC16 of TLV data - 2 bytes \- TLV data 2) Generate a key pair \[privA, pubA\] using secp256k1 curve in App, 3) Call OPEN\_SESSION command with P2 = 0x02 and \[pubA\] key as a parameter, 4) COS will generate own a key pair \[privB, pubB\] and return \[pubB\] as a response to OPEN\_SESSION command, 5) Calculate shared\_secret = privA \* pubB as per ECDH protocol, 6) Calculate protocol\_key = PBKDF2(SHA256(PIN1), UID, 50), where UID - ISO 14443-3 unique identifier, 7) Calculate session\_key = SHA256(shared\_secret | protocol\_key), 8) Payload = AES256(session\_key, tlv\_data). **Tangem COS strong encrypted response:** * Response\_Data – contains concatenated: \- Length of response TLV data - 2 bytes \- CRC16 of response TLV data - 2 bytes \- AES256( session\_key , response\_tlv\_data), * Status\_Word – command result (2 bytes, bigendian) CRC16 of TLV data should always be verified both by App and COS to exclude dealing with corrupted or tampered data. ### 4.6 OPEN\_SESSION command In case of encrypted communication, App should setup a session before calling any further command. OPEN\_SESSION command generates secret session\_key that is used by both host and card to encrypt and decrypt commands’ payload (see above). _Command INS code:_ **0xFF** #### 4.6.1 Fast Encryption * **P1=0x00** * **P2=0x01** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | ChallengeA | 0x1A | byte\[16\] | Host’s challenge | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _ChallengeB_ | 0x1B | byte\[16\] | Card’s challenge | | UID | 0x0B | byte\[4\] | _Version 2.30 and later._<br><br>ISO 14443-3 unique identifier – for compatibility with devices where UID is hidden | #### 4.6.2 Strong Encryption * **P1=0x00** * **P2=0x02** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _pubA_ | 0x1A | byte\[65\] | Public part of host key pair in ECDH | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _pubB_ | 0x1B | byte\[65\] | Public part of card key pair in ECDH | | UID | 0x0B | byte\[4\] | _Version 2.30 and later._<br><br>ISO 14443-3 unique identifier – for compatibility with devices where UID is hidden | ### 4.7 Pending security delay **Version 1.16 and later.** In case a non-zero delay is set in Pause\_Before\_PIN2 personalization parameter, the host app should continuously resend the same command request until the card executes it. After each interim request, the card will wait for ~1 second and respond with SW\_NEED\_PAUSE = 0x9789 and a TLV structure indicating remaining time of delay. **Version 1.21 and later.** The same mechanism applied in all commands to inform the host about all kinds of internal delays, including increasing delay on wrong PIN1 and PIN2. Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _CID_ | 0x01 | byte\[8\] | Card ID (only in version 1.19 and earlier) | | Pause | 0x1C | Uint16 | Remaining time, \[10 x ms\] | | SavedInNVM | 0x28 | 0 bytes | Version 2.30 and later.<br><br>Optional flag indicating that COS has saved the value of remaining security delay in NVM. | **Version 1.19 and earlier.** COS will return accordingly encrypted response if the command request has been encrypted with either fast or strong method. **Version 1.21 and later.** COS will return unencrypted response. If communication is lost during the delay pending, then COS will immediately lose the state of countdown timer and restart it from the beginning after next command request. Due to fluctuations of card’s CPU clock and NFC field, COS can follow Pause\_Before\_PIN2 quite approximately in the range of -10% - +75%. Therefore, the host app should refrain from displaying the exact remaining time and use an indicative progress bar instead. **Version 2.30 and later.** For compatibility with iOS 13 and later versions, COS saves the value of remaining security delay in NVM every 5-10 seconds. COS additionally returns flag SavedInNVM if this value is stored. After the NFC session between card and terminal has been lost or reset, COS will continue the security delay countdown from the value stored in NVM if the first command received by COS coincide with the last one received before the session reset.  5\. Personalization ------------------- These card parameters are defined by PERSONALIZE command: _CID, PIN1, PIN2, PIN3, Sign\_Method,_ _NDEF, Card\_Data,_ _Issuer\_Data\_PublicKey,_ _Issuer\_Transaction\_PublicKey,_ _Max\_Signatures, Settings\_Mask, Create\_Wallet\_At\_Personalize,_ _Is\_Activated, Pause\_Before\_PIN2_ This section describes CID, NDEF, and Card\_Data fields. ### 5.1 UID and CID _UID_ is 4-byte code required by ISO14443 standard. This code is randomly set only once during personalization process. It is never used in Tangem protocol except for NFC communication channel encryption key. _CID_ (Card ID) is a globally unique Tangem card number defined and printed (not embossed) by Tangem during personalization. It has 8 byte length and uses all hex digits (0..F). Example: ‘AA00 0000 0001 6675’. _CID_ is encoded as SSSS NNNN NNNN NNNX, where: * SSSS – batch number associated with the Issuer, * NN..NN – unique card number within the batch, * X – check digit according to Luhn algorithm, adapted to hex, see sample code in Appendix C. ### 5.2 NDEF records During personalization, the issuer can define data of a static _NDEF_ tag that will be emulated by COS if some NFC terminal (smartphone) will ever request such tag from the card. It is also possible to fully disable tag emulation. COS emulates NDEF format according to the NFC Forum standards: * NFC Forum Type 4 Tag Operation Specification \[NFCForum-TS-Type-4-Tag\_2.0\] * NFC Data Exchange Format (NDEF) Technical Specification \[NFCForum-TS-NDEF\_1.0\] Default Tangem NDEF consists of two records: 1\. URI, value - e.g. ‘https://tangem.com’ This record can be used to identify the card, even if there are no compatible applications installed on the smartphone. It is also used by iOS for background tag scanning. 2\. AAR (Android application record), value – e.g. ‘com.tangem.wallet’ for native Tangem application (not used in iOS). This record can be used to automatically open the corresponding App on the smartphone or to proceed to a correct issuer’s application page on Google Play Store, if it’s not installed on the smartphone. This tag must be used with caution because an attacker distributing counterfeit Tangem cards could potentially exploit it to mislead the user in downloading a counterfeit application. ### 5.3 Card\_Data Structure and payload of this nested TLV field shall be defined together by Tangem and the issuer during personalization. App shall accordingly parse _Card\_Data_ field that is returned by READ\_CARD command. The following minimum set of parameters is required to identify the card and the issuer, (native Tangem application will recognize these parameters): | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _Batch\_ID_ | 0x81 | byte\[2\], hex | Tangem internal manufacturing batch ID, should correspond with the data in Tangem’s card list (see Card attestation and UID and CID sections) | | _Manufacture\_Date\_Time_ | 0x82 | byte\[4\] | Timestamp of manufacturing should correspond with the data in Tangem’s card list (see Card attestation section).<br><br>Format: Year (2 bytes) \| Month (1 byte) \| Day (1 byte) | | _Issuer\_Name_ | 0x83 | string, utf8 | Name of the issuer | | _Blockchain\_Name_ | 0x84 | string, utf8 | Name of the blockchain (once personalized, the target blockchain is fixed for the whole life cycle) | | _Manufacturer\_Signature_ | 0x86 | byte\[64\] | Version 1.21 and later.<br><br>Signature of CID with the MANUFACTURER\_PRIVATE\_KEY<br><br>In some cases, signature of (CID \| Card\_PublicKey) with the MANUFACTURER\_PRIVATE\_KEY | | _ProductMask_ | 0x8A | byte | Version 2.30 and later<br><br>Mask of products enabled on card<br><br>0x01-Note, 0x02-Tag, 0x04-ID card | The issuer could append this list if more identifying parameters are required. For example, it would contain some data about a smart contact, if the issuer were going to store ERC20 tokens. For example, native Tangem application will recognize the following additional parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | _Token\_Symbol_ | 0xA0 | string, utf8 | Name of the token | | _Token\_Contract\_Address_ | 0xA1 | string, utf8 | Smart contract address | | _Token\_Decimal_ | 0xA2 | string, utf8 | Number of decimals in token value | 6\. Dynamic NDEF ---------------- Shall be supported ONLY on iOS versions 11 and 12. Other NFC smartphones shall not use this feature. Tangem card supports a special wallet validation mechanism for smartphones that can only read NDEF tags, specifically iPhones 7, 8, 10 with iOS version 11 or later. Issuer can enable it by setting _Use\_Dynamic\_NDEF_ flag in _Settings\_Mask_. In addition to two Tangem card NDEF records defined by personalization (see Personalization section for details), cards with dynamic NDEF will compose a third NDEF record for every new request of NDEF by smartphone. Dynamic NDEF has following structure: * NDEF type: NFC Forum External * Value: ‘tangem.com:wallet’ * Payload: \- Status\_Word – command result (2 bytes, bigendian), same result codes as for all commands: \- 0x9000 – OK \- 0x6A86 – TLV structure will not be returned because of some internal error, e.g. the card is protected by non-default _PIN1_ (meaning that card and wallet data is simply not accessible). \- TLV structure that contains: \- CID, Card\_Data, Card\_PublicKey, Health parameters, if there’s no wallet has been created (card’s Status is ‘Empty’), or \- A subset of parameters returned in responses of _READ\_CARD_ and _CHECK\_WALLET_ commands \- VERSION 1.19 AND LATER included _Wallet\_Signed\_Hashes_ field, \- VERSION 1.21 AND LATER included _Settings\_Mask_ and _Max\_Signatures_ fields, Dynamic NDEF works only if the card PIN1 is set to the default value. In this case, COS internally executes READ\_CARD and CHECK\_WALLET in order to compose the resulting TLV. The main point is that COS has to generate a random Challenge for _CHECK\_WALLET_ by itself, instead of receiving it from the application. This approach cannot guarantee full validation of the wallet, though provides a non-strict one that could be sufficient in some use cases. Some additional measures can alleviate the risk of attack of giving a counterfeit card or compromised wallet to a user who makes non-strict validation. First, the application can require to read dynamic NDEF of the same card many times to ensure the card generates different Challenges. In addition, there’s always a risk for the attacked that the user has another fully functional NFC smartphone nearby. **Version 1.21 and later.** COS adapts to the limitation of tag response time in iOS 11.3.1. During the execution of CREATE\_WALLET command, COS internally executes CHECK\_WALLET twice to pre-compute and store two wallet signatures. If COS is unable to respond with the full TLV because of the host breaks the connection, it will respond with one of two precomputed signatures at the next attempt and toggle between two precomputed signature values at every next attempt. Although it is even less safe wallet validation method, it allows to protect against cheap clones using static programmable NFC tags. **Version 2.01 and later.** Issuer can disable precomputed NDEF by setting Disable\_PrecomputedNDEF flag in Settings\_Mask. 7\. Activation -------------- This mechanism allows safe physical transportation of the card through non-trusted environment. It disables most of card’s commands from the moment of personalization and until the issuer confirms to COS that the card has been activated. To use activation mode, the issuer should disable _Is\_Activated_ flag during personalization. If it’s done, the card will accept only these three commands: * READ\_CARD command will return only these fields: _\- CID,_ _\- Manufacturer\_ID,_ _\- Status,_ _\- Card\_Data,_ _\- Settings\_Mask,_ _\- Issuer\_Data\_PublicKey._ * READ\_ISSUER\_DATA, * ACTIVATE\_CARD ACTIVATE\_CARD command provides guaranteed mutual update of activation state in both COS and issuer’s activation back-end. Activation process works as follows: 1. App calls READ\_CARD command and recognizes Is\_Activated flag is disabled, 2. App sends a request containing CID and Activation\_Seed to issuer’s activation back-end, 3. Issuer’s activation back-end activates (and optionally top-ups) the card and sends a signed response to App, 4. App calls ACTIVATE\_CARD command with the issuer’s response as a parameter, 5. COS parses issuer’s response and verifies its signatures; if it’s OK, the COS renders itself to activated (fully functional) state. In case of any interruption, App can safely restart this process from the beginning and repeat it until the card is activated. Therefore, it is guaranteed that the issuer’s back-end will have completed all required activation operations before the card is switched to activated state.   8\. Commands ------------ Tangem COS provides 15 commands available to end user’s host application and PERSONALIZE command that sets main parameters in the beginning of the life cycle. The end user might optionally restrict access to the whole card and all commands by setting user’s PIN1 code. By default, all cards have PIN1 set to ‘000000’, so that every host application on any NFC smartphone could obtain card and wallet data. In the beginning of communication session, App should obtain card CID by calling READ\_CARD command with hashed default PIN1. If the user has set a non-default PIN1, READ\_CARD command will return Status Word SW\_INVALID\_PARAMS (= 0x6A86). In such case, the application should request correct PIN1 from the user and call READ\_CARD command again, this time with hashed PIN1 enter by the user. Once CID is obtained by READ\_CARD command, the application can call all other commands that require CID and hashed PIN1 as parameters. All cards will require submitting correct user’s PIN2 code and (depending on personalization parameters) printed CVC code in order to sign a transaction or to perform other commands entailing change of the card state.App should ask the user to enter PIN2 and/or CVC before sending such commands to the card. There should be no default value for PIN2 code, if either CVC or very long Pause\_Before\_PIN2 delay are not used. See Security section for more details. Commands can return the following Status Words in the result of execution: * SW\_PROCESS\_COMPLETED = 0x9000 \- successful execution * SW\_INVALID\_PARAMS = 0x6A86 \- wrong or not sufficient parameters in TLV request, or wrong PIN1/PIN2 * SW\_ERROR\_PROCESSING\_COMMAND = 0x6286 \- internal error, incl. wrong issuer signature * SW\_INVALID\_STATUS = 0x6985 \- command can not be executed in current card status * SW\_INS\_NOT\_SUPPORTED = 0x6D00 \- wrong command INS code ### 8.1 ACTIVATE\_CARD This command activates the card if it requires activation (Is\_Activated flag is disabled). The application should go through an activation process in coordination with the issuer’s activation back-end (see 'Activation' section for details). _Command INS code:_ **0xFE** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card,<br><br>Default value should not be used with this command | | Reset\_PIN1 | 0x36 | byte\[1\] | 0 – Do not change PIN1 used for activation (for calling this command)<br><br>1 – Reset PIN1 to default value (‘000000’) | | Activation\_Signature | 0x34 | byte\[64\] | Concatenated (_CID_ \| _Activation\_Seed_ \| _Reset\_PIN1_) signed with _Issuer\_Transaction\_PrivateKey_;<br><br>If the signature is successfully verified with _Issuer\_Transaction\_PublicKey_, then Is\_Activated flag will be enabled | Response: Same as in _READ\_CARD_ command ### 8.2 READ\_CARD This command returns all data about the card and the wallet, including unique card number (CID) that has to be submitted while calling all other commands. Therefore, READ\_CARD should always be used in the beginning of communication session between host and Tangem card. In order to obtain card’s data, App should call READ\_CARD command with correct PIN1 value as a parameter. The card will not respond if wrong PIN1 has been submitted. See Security section for details. _Command INS code:_ **0xF2** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Terminal\_Public\_Key | 0x5C | byte\[65\] | VERSION 2.30 AND LATER<br><br>Optional public key of linked host terminal (see ‘Linked terminal’ section)<br><br>If the card was linked to the certain host terminal, Terminal\_Public\_Key would have to be passed. Otherwise, the card will be unlinked, and the next sign command will perform the security delay mechanism.<br><br>See Linked terminal section for more details. | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Manufacturer\_Name | 0x20 | string, utf8 | Name of Tangem card manufacturer<br><br>_Fixed: ‘Smart Cash’_ | | Status | 0x02 | byte | Current status of the card<br><br>\[1 - Empty, 2 - Loaded, 3- Purged\] | | Firmware\_Version | 0x80 | string, utf8 | Version of Tangem COS | | Card\_PublicKey | 0x03 | byte\[65\] | Public key that is used to authenticate the card against manufacturer’s database. It is generated one time during card manufacturing. See Security section for more details. | | Settings\_Mask | 0x0A | byte\[2\]<br><br>**Version 2.01 and later.**<br><br>byte\[2\] or byte\[4\] | Card settings defined by personalization (bit mask: 0 – Enabled, 1 – Disabled):<br><br>**Is\_Reusable = 0x0001**<br><br>Defines what happens when user calls PURGE\_WALLET command:<br><br>_0 - Card will switch to Purged state_<br><br>_1 - Card will switch to Empty state and let create a new wallet again_<br><br>**Use\_Activation = 0x0002**<br><br>VERSION 2.01 AND LATER<br><br>**Prohibit\_Purge\_Wallet = 0x0004**<br><br>0 – Card will accept PURGE\_WALLET command<br><br>1 – Card will reject PURGE\_WALLET command<br><br>**Use\_Block = 0x0008**<br><br>**Allow\_SET\_PIN1 = 0x0010**<br><br>Is user allowed to change PIN1 with SET\_PIN command<br><br>**Allow\_SET\_PIN2 = 0x0020**<br><br>Is user allowed to change PIN2 with SET\_PIN command<br><br>**Use\_CVC = 0x0040**<br><br>All commands requiring PIN2 will also require additional CVC code printed on the card<br><br>**Prohibit\_Default\_PIN1 = 0x0080**<br><br>SET\_PIN commands will not change PIN1 to default value (‘000000’).<br><br>~~**Use\_One\_CommandAtTime = 0x0100**<br><br>Card will execute only one command during one communication session, thus requiring user to physically take the card away from the host after each action (all commands except for READ\_CARD).<br>~~<br>**Use\_NDEF = 0x0200**<br><br>Whether the card should emulate NDEF. In default configuration, two NDEF records are loaded during personalization: (1) Tangem web site address, (2) name of Android App package in Google Play Store.<br><br>~~**Use\_Dynamic\_NDEF = 0x0400**<br><br>0 – Disable dynamic generation of NDEF for iOS. See Dynamic NDEF section for more details.<br><br>1 – Enable dynamic NDEF for iOS.<br>~~<br>**Smart\_Security\_Delay = 0x0800**<br><br>Security delay Pause\_Before\_PIN2 will not be applied if PIN2 is not default.<br><br>**Allow\_Unencrypted = 0x1000**<br><br>Whether the card supports unencrypted NFC communication. See NFC communication section for more details.<br><br>**Allow\_Fast\_Encryption = 0x2000**<br><br>Whether the card supports fast encrypted NFC communication. See NFC communication section for more details.<br><br>**Protect\_Issuer\_Data\_Against\_Replay = 0x4000**<br><br>VERSION 1.21 AND LATER<br><br>0 – No replay protection on write issuer data<br><br>1 – Enable replay protection on write issuer data (card will require additional Issuer\_Data\_Counter incremented on each write)<br><br>**Allow\_Select\_Blockchain = 0x8000**<br><br>VERSION 2.01 AND LATER<br><br>0 – Wallet elliptic curve and blockchain information stored during PERSONALIZE command and never change<br><br>1 – Wallet elliptic curve and blockchain information can be changed on CREATE\_WALLET command<br><br>~~**Disable\_Precomputed\_NDEF = 0x00010000**<br><br>0 – Enable precomputed dynamic NDEF to work around iPhone 7+ NFC bug.<br><br>1 – Disable precomputed dynamic NDEF. See Dynamic NDEF section for more details.<br>~~<br>**Skip\_Security\_Delay\_If\_Validated\_By\_Issuer = 0x00020000**<br><br>VERSION 2.05 AND LATER<br><br>0 – Enforce security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5).<br><br>1 – Skip security delay in SIGN command if the issuer validates the transaction (for signing methods 2, 3, 4 and 5).<br><br>**Skip\_Check\_PIN2\_and\_CVC\_If\_Validated\_By\_Issuer = 0x00040000**<br><br>VERSION 2.05 AND LATER<br><br>0 – Require and check PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5).<br><br>1 – Skip checking PIN2 and CVC in SIGN command if the issuer validates the transaction (for signing method 2, 3, 4 and 5).<br><br>**Skip\_Security\_Delay\_If\_Validated\_By\_Linked\_Terminal = 0x00080000**<br><br>VERSION 2.30 AND LATER<br><br>1 - Store Terminal\_PublicKey public key of linked terminal no each SIGN command, skip security delay if valid signature of transaction is made with Terminal\_PrivateKey is provided in SIGN command<br><br>~~**Restrict\_Overwrite\_Issuer\_Extra\_Data = 0x00100000**<br><br>VERSION 2.30 AND LATER<br><br>1 – prohibit overwriting Issuer\_Extra\_Data<br>~~ | | Card\_Data | 0x0C | byte\[0..512\] | Detailed information about card contents. Format is defined by the card issuer. Cards complaint with Tangem Wallet application should have TLV format described in Personalization section. | | Issuer\_Data\_PublicKey | 0x30 | byte\[65\] | Public key that is used by the card issuer to sign Issuer\_Data field. See Security section for more details. | | Curve\_ID | 0x05 | string, utf8 | Explicit text name of the elliptic curve used for all wallet key operations.<br><br>Supported curves: ‘secp256k1’, VERSION 2.01 AND LATER - ‘ed25519’ | | Max\_Signatures | 0x08 | uint32 | Total number of signatures allowed for the wallet when the card was personalized. | | Signing\_Method | 0x07 | byte | Defines what data should be submitted to SIGN command.<br><br>\[0 - sign hash, 1 - sign raw transaction, 2 - sign hash signed by issuer, 3 - sign raw signed by issuer ~~, 4 - sign hash signed by issuer and update Issuer\_Data, 5 - sign raw signed by issuer and update Issuer\_Data~~\]<br><br>**Version 2.05 and later.**<br><br>Signing\_Method can specify a set of allowed methods. In this case, the highest bit in Signing\_Method value must be set to 1 and each of bits 0..5 must be set to enable corresponding signing methods. For example, if Signing\_Method = 0x95, COS allows Signing\_Method = 0, Signing\_Method = 2, Signing\_Method = 4; if Signing\_Method = 0xBF – all methods are allowed.<br>~~<br>**Version 2.30 and later.**<br><br>New Signing\_Method value ‘6’ – sign POS transactions (or bit #6 if multiple signing methods are allowed)~~ | | Pause\_Before\_PIN2 | 0x09 | byte\[2\] | Delay in seconds before COS executes commands protected by PIN2. | | Wallet\_PublicKey | 0x60 | byte\[65\]<br><br>**Version 2.01 and later**<br><br>byte\[65\] or byte\[32\] | Public key of the blockchain wallet. Value returned only if the wallet has already been created by CREATE\_WALLET command. See Security section for more details. | | Wallet\_Remaining\_Signatures | 0x62 | uint32 | Remaining number of SIGN operations before the wallet will stop signing transactions. Value returned only if the wallet has already been created by CREATE\_WALLET command. | | Wallet\_Signed\_Hashes | 0x63 | uint32 | VERSION 1.16 AND LATER<br><br>Total number of signed single hashes returned by the card in _SIGN_ command responses since card personalization. Sums up array elements within all _SIGN_ commands. | | Health | 0x0F | byte\[1\] | Any non-zero value indicates that the card experiences some hardware problems. User should withdraw the value to other blockchain wallet as soon as possible. Non-zero Health tag will also appear in responses of all other commands. | | Is\_Activated | 0x3A | byte\[1\] | Whether the card requires issuer’s confirmation of activation.<br><br>0 – card will require issuer’s confirmation of activation,<br><br>otherwise this field will not be returned (card is activated and operational).<br><br>See _ACTIVATE\_CARD_ command for more details. | | Activation\_Seed | 0x3B | byte\[16\] | A random challenge generated by PERSONALIZE command that should be signed and returned to COS by the issuer to confirm the card has been activated. See ACTIVATE\_CARD command for more details.<br><br>This field will not be returned if the card is activated. | Note: Parameters are included in the response depending on the card state: * In the ‘New’ state: CID, Manufacturer\_ID, Firmware\_Version and Status fields are included, * After personalization and before activation: additionally, Card\_Data, Settings\_Mask, Issuer\_Data\_PublicKey, Is\_Activated, Activation\_Seed fields, * After personalization and activation, all other parameters are included, except for Wallet\_PublicKey and Wallet\_Remaining\_Signatures. * After a wallet is created, the Wallet\_PublicKey and Wallet\_Remaining\_Signatures parameters are included. ### 8.3 CREATE\_WALLET This command will create a new wallet on the card having ‘Empty’ state. A key pair Wallet\_PublicKey / _Wallet\_PrivateKey_ is generated and securely stored in the card. App will need to obtain _Wallet\_PublicKey_ from the response of CREATE\_WALLET or READ\_CARD commands and then transform it into an address of corresponding blockchain wallet according to a specific blockchain algorithm. _Wallet\_PrivateKey_ is never revealed by the card and will be used by SIGN and CHECK\_WALLET. Remaining\_Signature is set to Max\_Signatures. _Command INS code:_ **0xF8** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN2 | 0x11 | byte\[32\] | Hashed user’s PIN2 code for signing and state-changing operations. See Security section for more details. | | CVC | 0x19 | byte\[3\] | Optional 3-digit code printed on the card. Required if Use\_CVC flag is set in Settings\_Mask. | | VERSION 2.01 AND LATER<br><br>If _Allow\_Select\_Blockchain_ flag is set in _Settings\_Mask_ then the card allows changing type of blockchain in CREATE\_WALLET command. The following parameters should must appended: | | | | | Curve\_ID | 0x05 | string, utf8 | New explicit text name of the elliptic curve used for all wallet key operations.<br><br>Supported curves: ‘secp256k1’, ‘ed25519’ | | Card\_Data | 0x0C | byte\[0..512\] | Update to information about card contents in TLV format described in Personalization section. Tags that can be updated: Blockchain\_Name, Token\_Symbol, Token\_Contract\_Address, Token\_Decimal<br><br>If Card\_Data contains other fields then command will fail and return error SW\_INVALID\_PARAMS. | | Issuer\_Data\_Signature | 0x33 | byte\[64\] | Issuer’s signature (with ‘secp256k1’ and _Issuer\_Data\_PrivateKey_) of SHA256-hashed Curve\_ID concatenated with Card\_Data: SHA256(Curve\_ID \| Card\_Data). | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Status | 0x02 | byte | Current status of the card<br><br>\[1 - Empty, 2 - Loaded, 3- Purged\] | | Wallet\_PublicKey | 0x60 | byte\[65\]<br><br>VERSION 2.01 AND LATER<br><br>or byte\[32\] | Public key of a newly created blockchain wallet. See Security section for more details. | ### 8.4 CHECK\_WALLET This command proves that the card possesses _Wallet\_PrivateKey_ corresponding to _Wallet\_PublicKey_. Standard challenge/response scheme is used. _Command INS code:_ **0xF9** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Challenge | 0x16 | byte\[16\] | Random challenge generated by host application | | VERSION 2.01 AND LATER<br><br>Self-attestation is supported. If the following additional parameter is specified, CHECK\_WALLET will return Wallet\_PublicKey signed by Card\_PrivateKey: | | | | | Public\_Key\_Challenge | 0x14 | byte\[16\] or byte\[0\] | Optional: Random challenge generated by host application. If specified, this field presents then card will return Card\_Signature field in response | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Salt | 0x17 | byte\[16\] | Random salt generated by the card | | Wallet\_Signature | 0x61 | byte\[64\] | Signature of hashed concatenated Challenge and Salt with _Wallet\_PrivateKey_<br><br>For ‘secp256k1’ curve SHA256 is used, signature of SHA256(Challenge \| Salt)<br><br>For ‘ed25519’ curve SHA512 is used, signature of SHA512(Challenge \| Salt) | | VERSION 2.01 AND LATER<br><br>If Public\_Key\_Challenge had been submitted: | | | | | Check\_Wallet\_Counter | 0x64 | byte\[4\] | Counter of CHECK\_WALLET command executions. A very big value of this counter may indicate a hacking attempts. | | Public\_Key\_Salt | 0x15 | byte\[16\] | Random salt generated by the card<br><br>Optional, if in request presents non-empty Public\_Key\_Challenge | | Card\_Signature | 0x04 | byte\[64\] | Signature of hashed concatenated _Wallet\_PublicKey_, _Public\_Key\_Challenge_, _Public\_Key\_Salt_ with _Card\_PrivateKey_<br><br>Optional, if in request presents _Public\_Key\_Challenge_<br><br>_SHA256(Wallet\_PublicKey \| Public\_Key\_Challenge \| Public\_Key\_Salt)_ signed with _Card\_PrivateKey_, if in request presents non-empty Public\_Key\_Challenge<br><br>or<br><br>_SHA256(Wallet\_PublicKey)_ signed with _Card\_PrivateKey_, if in request presents empty Public\_Key\_Challenge | ### 8.5 SET\_PIN This command changes PIN1 and PIN2 passwords if it is allowed by Allow\_SET\_PIN1 and Allow\_SET\_PIN2 flags in Settings\_Mask. Host application can submit unchanged passwords (New\_PIN1 = PIN1 and New\_PIN2 = PIN2) in order to check its correctness. Depending on the result, Status\_Word in the command response will have these values: _SW\_PINS\_NOT\_CHANGED = 0x9000_ _SW\_PIN1\_CHANGED = 0x9001_ _SW\_PIN2\_CHANGED = 0x9002_ _SW\_PINS\_CHANGED = 0x9003_ VERSION 2.30 AND LATER _SW\_PIN3\_CHANGED = 0x9004_ _SW\_PINS\_CHANGED = 0x90XX, XX – changed PINs mask (0x01-PIN1, 0x02-PIN2, 0x04-PIN3)_ _Command INS code:_ **0xFA** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN2 | 0x11 | byte\[32\] | Hashed user’s PIN2 code for signing and state-changing operations. See Security section for more details. | | CVC | 0x19 | byte\[3\] | Optional 3-digit code printed on the card.<br><br>Required if Use\_CVC flag is set in Settings\_Mask. | | New\_PIN1 | 0x12 | byte\[32\] | New hashed user’s PIN1 code to access the card. | | New\_PIN2 | 0x13 | byte\[32\] | New hashed user’s PIN2 code for signing and state-changing operations. | | New\_PIN3 | 0x1E | byte\[32\] | VERSION 2.30 AND LATER<br><br>Optional new hashed user’s PIN3 code for confirm POS operations. | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | ### 8.6 SIGN Depending on Signing\_Method parameter defined during personalization, this command signs following data using _Wallet\_PrivateKey_: * array of transaction hashes (Signing\_Method = 0) * single raw transaction (Signing\_Method = 1) In case the card issuer supports 2FA (see in Security section), COS will firstly verify issuer’s signature of transaction hash before signing transaction hash using _Wallet\_PrivateKey_. Following data should be submitted to SIGN command in this case: * array of transaction hashes signed by the issuer (Signing\_Method = 2), * single raw transaction signed by the issuer (Signing\_Method = 3), ~~In case the card issuer requires the card to store additional data (e.g. wallet balance, SPV proof, timestamps, etc. – see details in Security section), COS will verify (1) issuer’s signature of hash of concatenated transaction hashes and Issuer\_Data hash, and (2) issuer’s signature of Issuer\_Data hash, and then proceed to signing transaction hash using _Wallet\_PrivateKey_. Following data should be submitted to SIGN command in this case:~~ * ~~array of transaction hashes and issuer data signed by the issuer (Signing\_Method = 4),~~ * ~~single raw transaction and issuer data signed by the issuer (Signing\_Method = 5),~~ The raw transaction will be hashed by a hash function ‘Hash\_Name’ before signing. In the generic COS version described here, raw transactions are not parsed, analyzed or transformed by COS. Simultaneous signing of array of hashes in a single SIGN command is required to support Bitcoin-type multi-input blockchains. SIGN command will return a corresponding array of signatures. If COS cannot validate issuer’s signature where it is required, SIGN command will return Status word SW\_ERROR\_PROCESSING\_COMMAND= 0x6286. After data is signed and SIGN response is successfully sent to the host, COS decreases Wallet\_Remaining\_Signatures counter by 1. When Remaining\_Signatures counter reaches zero, SIGN command will no longer generate any signatures for the wallet. COS always stores cached signature(s) generated by the last SIGN command and return this cached result if SIGN command is called again with empty parameters. In this way, the signature(s) can be restored in case App has lost the previous SIGN response for any reason. **Version 2.05 and later.** Signing\_Method can specify a set of allowed methods. In this case, the highest bit in Signing\_Method value must be set to 1 and each of bits 0..5 must be set to enable corresponding signing methods: bit 0 (lowest) – allow Signing\_Method = 0, bit 1 – allow Signing\_Method = 1 and so on. For example, if Signing\_Method = 0x95 COS allow Signing\_Method = 0, Signing\_Method = 2, Signing\_Method = 4; if Signing\_Method = 0xBF – all methods are allowed. If more than one signing method is allowed, the application can select a method by providing an appropriate set of parameters for SIGN command. (Signing\_Methods = 0, 1, 2, 3) _Command INS code:_ **0xFB** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | PIN2 | 0x11 | byte\[32\] | Hashed user’s PIN2 code for signing and state-changing operations. See Security section for more details. | | CVC | 0x19 | byte\[3\] | Optional 3-digit code printed on the card.<br><br>Required if Use\_CVC flag is set in Settings\_Mask. | | Transaction\_Hash\_Size | 0x51 | byte\[1\] | Length of a single hash to be signed (0x20 for SHA256).<br><br>Required if Signing\_Method = 0, 2, 4 | | Transaction\_Hash | 0x50 | byte\[n\*hash\_size\] | Concatenated array of hashes to be signed.<br><br>Required if Signing\_Method = 0, 2, 4 | | Transaction\_Raw | 0x52 | byte\[1..512\] | Raw transaction to be hashed and signed.<br><br>Required if Signing\_Method = 1, 3 ~~, 5~~ | | Hash\_Name | 0x06 | byte\[5..9\] | Text name of hash function to hash raw transaction, supported value are ‘sha-256’, ‘sha-1’, ‘sha-224’, ‘sha-384’, ‘sha-512’. It’s possible to specify a double hashing by add ‘x2’ to the hash function name.<br><br>Required if Signing\_Method = 1, 3 ~~, 5~~ | | ~~Issuer\_Data~~ | ~~0x32~~ | ~~byte\[1..512\]~~ | ~~Some issuer’s data that must be stored in the card at the moment of signing the transaction. May contain wallet balance, SPV proof, timestamps, etc. This data is never parsed, analyzed or transformed by COS. See Security section for more details.~~ | | ~~Issuer\_Data\_Counter~~ | 0x35 | int\[4\] | ~~VERSION 1.21 AND LATER<br><br>An internal counter received from READ\_ISSUER\_DATA command. Must be signed by the issuer together with Issuer\_Data.<br><br>Required if Signing\_Method = 4, 5.~~ | | Issuer\_Transaction\_Signature | 0x34 | byte\[64\] | _If Signing\_Method = 2_<br><br>issuer’s signature of a hash of concatenated array of transaction hashes:<br><br>SHA256( tx\_hash\_1 \| … \| tx\_hash\_n)<br><br>_If Signing\_Method = 3_<br><br>issuer’s signature of a hash of raw transaction: SHA256(tx\_raw)<br>~~<br>_If Signing\_Method = 4_<br><br>issuer’s signature of a hash of concatenated array of transaction hashes and Issuer\_Data: SHA256( tx\_hash\_1 \| … \| tx\_hash\_n \| (Issuer\_Data) )<br><br>_If Signing\_Method = 5_<br><br>issuer’s signature of a hash of concatenated hash of raw transaction and Issuer\_Data: SHA256( SHA256(tx\_raw) \| ( Issuer\_Data) )~~ | | ~~Issuer\_Data\_Signature~~ | 0x33 | byte\[64\] | ~~Required if Signing\_Method = 4, 5.<br><br>**Version 1.19 and earlier.**<br><br>Issuer’s signature of SHA256-hashed Issuer\_Data concatenated with CID:<br><br>SHA256(CID \| Issuer\_Data)<br><br>**Version 1.21 and later.**<br><br>Issuer’s signature of SHA256-hashed Issuer\_Data concatenated with CID and Issuer\_Data\_Counter :<br><br>SHA256(CID \| Issuer\_Data \| Issuer\_Data\_Counter)~~ | | Terminal\_PublicKey | 0x5C | byte\[65\] | VERSION 2.30 AND LATER<br><br>Optional public key of linked host terminal (see ‘Linked terminal’ section)<br><br>Only for Signing\_Method = 0, 1 | | Terminal\_Transaction\_Signature | 0x57 | byte\[64\] | VERSION 2.30 AND LATER<br><br>Optional transaction signature by linked host terminal (see ‘Linked terminal’ section)<br><br>Only for Signing\_Method = 0, 1<br><br>_If Signing\_Method = 0_<br><br>signature of a hash of concatenated array of transaction hashes:<br><br>SHA256( tx\_hash\_1 \| … \| tx\_hash\_n)<br><br>_If Signing\_Method = 1_<br><br>signature of a hash of raw transaction: SHA256(tx\_raw) | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Signature | 0x40 | byte\[n\*64\] | Array of resulting signatures that App should embed into a raw transaction according to a transaction format of an appropriate blockchain. | | Wallet\_Remaining\_Signatures | 0x62 | uint32 | Remaining number of SIGN operations before the wallet will stop signing transactions. | | Wallet\_Signed\_Hashes | 0x63 | uint32 | VERSION 1.16 AND LATER<br><br>Total number of signed single hashes returned by the card in SIGN command responses since card personalization. Sums up array elements within all SIGN commands. | ### 8.7 READ\_ISSUER\_DATA This command returns 512-byte Issuer\_Data field and its issuer’s signature. See details in Issuers section. Issuer\_Data is never changed or parsed by the executable code the Tangem COS. The issuer defines purpose of use, format and payload of Issuer\_Data. For example, this field may contain information about wallet balance signed by the issuer or additional issuer’s attestation data. _Command INS code:_ **_0xF7_** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Issuer\_Data | 0x32 | byte\[1..512\] | Data defined by issuer | | Issuer\_Data\_Signature | 0x33 | byte\[64\] | Issuer’s signature of Issuer\_Data with _Issuer\_Data\_PrivateKey_<br><br>**Version 1.19 and earlier**<br><br>Issuer’s signature of SHA256-hashed CID concatenated with Issuer\_Data:<br><br>SHA256(CID \| Issuer\_Data)<br><br>**Version 1.21 and later**<br><br>When flag Protect\_Issuer\_Data\_Against\_Replay set in Settings\_Mask then signature of SHA256-hashed CID Issuer\_Data concatenated with and Issuer\_Data\_Counter :<br><br>SHA256(CID \| Issuer\_Data \| Issuer\_Data\_Counter) | | Issuer\_Data\_Counter | 0x35 | int\[4\] | VERSION 1.21 AND LATER<br><br>An optional counter that protect issuer data against replay attack. When flag Protect\_Issuer\_Data\_Against\_Replay set in Settings\_Mask then this value is mandatory and must increase on each execution of WRITE\_ISSUER\_DATA command. | ~~#### 8.7.1 Read issuer extra data~~ ~~VERSION 2.30 AND LATER~~ ~~This command retrieves Issuer\_Extra\_Data field and its issuer’s signature. See details in ‘Issuers’ section.~~ ~~Issuer\_Extra\_Data is never changed or parsed by the executable code the Tangem COS. The issuer defines purpose of use, format and payload of Issuer\_Extra\_Data. For example, this field may contain photo or biometric information for ID card product. Because of the large size of Issuer\_Extra\_Data, a series of these commands have to be executed to read the entire Issuer\_Extra\_Data.~~ _Command INS code:_ **0xF7** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Mode | 0x23 | byte | 0 or omitted – return Issuer\_Data<br><br>1 – return Issuer\_Extra\_Data | | Offset | 0x24 | uint16 | Offset in Issuer\_Extra\_Data to requested data part.<br><br>Only for reading Issuer\_Extra\_Data (Mode=1) | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Size | 0x25 | uint16 | Size of all Issuer\_Extra\_Data field<br><br>Returns only for reading Issuer\_Extra\_Data (Mode=1) and Offset=0 | | Issuer\_Data or<br><br>Issuer\_Extra\_Data | 0x32 | byte\[1..\] | Data defined by issuer (all Issuer\_Data field for Mode=0 or part of Issuer\_Extra\_Data for Mode=1) | | Issuer\_Data\_Signature or<br><br>Issuer\_Extra\_Data\_Signature | 0x33 | byte\[64\] | Issuer’s signature of Issuer\_Data (Mode=0) or Issuer\_Extra\_Data (Mode=1) with _Issuer\_Data\_PrivateKey_<br><br>If flags Protect\_Issuer\_Data\_Against\_Replay and Restrict\_Overwrite\_Issuer\_Extra\_Data aren’t set in Settings\_Mask then signature of SHA256-hashed CID concatenated with Issuer\_Data or Issuer\_Extra\_Data:<br><br>SHA256(CID \| Issuer\_Data) or SHA256(CID \| Issuer\_Extra\_Data).<br><br>Otherwise the signature of SHA256-hashed CID concatenated with Issuer\_Data or Issuer\_Extra\_Data and Issuer\_Data\_Counter or Issuer\_Extra\_Data\_Counter:<br><br>SHA256(CID \| Issuer\_Data \| Issuer\_Data\_Counter) or<br><br>SHA256(CID \| Issuer\_Extra\_Data \| Issuer\_Data\_Counter)<br><br>For Mode=1 this value return only with last part of Issuer\_Extra\_Data and size of data part is determined by free space in communication buffer. | | Issuer\_Data\_Counter or<br><br>Issuer\_Extra\_Data\_Counter | 0x35 | int\[4\] | An optional counter that protect issuer data against replay attack. When flags Protect\_Issuer\_Data\_Against\_Replay or Restrict\_Overwrite\_Issuer\_Extra\_Data set in Settings\_Mask then this value is mandatory and must increase on each execution of WRITE\_ISSUER\_DATA command.<br><br>There are two independent counters in COS to protect both Issuer\_Data and Issuer\_Extra\_Data.<br><br>For Mode=1 this value return only with last part of Issuer\_Extra\_Data. | ### 8.8 WRITE\_ISSUER\_DATA This command write 512-byte Issuer\_Data field and its issuer’s signature. See details in Issuers section. Issuer\_Data is never changed or parsed by the executable code the Tangem COS. The issuer defines purpose of use, format and payload of Issuer\_Data. For example, this field may contain information about wallet balance signed by the issuer or additional issuer’s attestation data. _Command INS code:_ **0xF6** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Issuer\_Data | 0x32 | byte\[1..512\] | Data defined by issuer | | Issuer\_Data\_Signature | 0x33 | byte\[64\] | Issuer’s signature of Issuer\_Data with _Issuer\_Data\_PrivateKey_<br><br>**Version 1.19 and earlier**<br><br>Issuer’s signature of SHA256-hashed Issuer\_Data concatenated with CID:<br><br>SHA256(CID \| Issuer\_Data)<br><br>**Version 1.21 and later**<br><br>When flag Protect\_Issuer\_Data\_Against\_Replay set in Settings\_Mask then issuer’s signature of SHA256-hashed Issuer\_Data concatenated with CID and Issuer\_Data\_Counter :<br><br>SHA256(CID \| Issuer\_Data \| Issuer\_Data\_Counter) | | Issuer\_Data\_Counter<br><br>VERSION 1.21 AND LATER | 0x35 | int\[4\] | An optional counter that protect issuer data against replay attack. When flag Protect\_Issuer\_Data\_Against\_Replay set in Settings\_Mask then this value is mandatory and must increase on each execution of WRITE\_ISSUER\_DATA command. | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | ~~#### 8.8.1 Write issuer extra data~~ VERSION 2.30 AND LATER This command writes Issuer\_Extra\_Data field and its issuer’s signature. See details in Issuers section. Issuer\_Extra\_Data is never changed or parsed by the executable code the Tangem COS. The issuer defines purpose of use, format and payload of Issuer\_Extra\_Data. For example, this field may contain a photo or biometric information for ID card products. Because of the large size of Issuer\_Extra\_Data, a series of these commands have to be executed to write entire Issuer\_Extra\_Data. _Command INS code:_ **0xF6** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Mode | 0x23 | byte | 0 or omitted – write Issuer\_Data<br><br>1 – start write Issuer\_Extra\_Data<br><br>2 – write part of Issuer\_Extra\_Data<br><br>3 – finalize write Issuer\_Extra\_Data | | Size | 0x25 | uint16 | Size of all Issuer\_Extra\_Data field<br><br>Only for start writing Issuer\_Extra\_Data (Mode=1) | | Issuer\_Data | 0x32 | byte\[1..\] | Data defined by issuer (all Issuer\_Data field for Mode=0 or part of Issuer\_Extra\_Data for Mode=2) | | Issuer\_Data\_Signature | 0x33 | byte\[64\] | Issuer’s signature with _Issuer\_Data\_PrivateKey_ of:<br><br>_for Mode=0:_<br><br>When flag Protect\_Issuer\_Data\_Against\_Replay set in Settings\_Mask then issuer’s signature of SHA256-hashed Issuer\_Data concatenated with CID and Issuer\_Data\_Counter :<br><br>SHA256(CID \| Issuer\_Data \| Issuer\_Data\_Counter)<br><br>_for Mode=1:_<br><br>If flags Protect\_Issuer\_Data\_Against\_Replay and Restrict\_Overwrite\_Issuer\_Extra\_Data are not set in Settings\_Mask then signature of SHA256-hashed CID concatenated with Size:<br><br>SHA256(CID \| Size).<br><br>Otherwise signature of SHA256-hashed CID concatenated with Issuer\_Extra\_Data\_Counter and Size:<br><br>SHA256(CID \| Issuer\_Data\_Counter \| Size)<br><br>_for Mode=3:_<br><br>If flags Protect\_Issuer\_Data\_Against\_Replay and Restrict\_Overwrite\_Issuer\_Extra\_Data aren’t set in Settings\_Mask then signature of SHA256-hashed CID concatenated with Issuer\_Extra\_Data:<br><br>SHA256(CID \| Issuer\_Extra\_Data).<br><br>Otherwise the signature of SHA256-hashed CID concatenated with Issuer\_Extra\_Data and Issuer\_Extra\_Data\_Counter:<br><br>SHA256(CID \| Issuer\_Extra\_Data \| Issuer\_Data\_Counter) | | Issuer\_Data\_Counter | 0x35 | int\[4\] | An optional counter that protect issuer data against replay attack. When flag Protect\_Issuer\_Data\_Against\_Replay or Restrict\_Overwrite\_Issuer\_Extra\_Data set in Settings\_Mask then this value is mandatory and must increase on each execution of WRITE\_ISSUER\_DATA command. | | Offset | 0x24 | uint16 | Offset in Issuer\_Extra\_Data to requested data part.<br><br>Only for writing part of Issuer\_Extra\_Data (Mode=2) | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | ### 8.9 VERIFY\_CODE This command challenges the card to prove integrity of COS binary code. For this purpose, App should have a special ‘hash library’ publicly provided by Tangem. Approx. size of the library is 5Mb. It contains ~150.000 precalculated SHA512 hashes of COS binary code segments. VERIFY\_CODE command internally reads a segment of COS binary code beginning at Code\_Page\_Address and having length of \[64 x Code\_Page\_Count\] bytes. Then it appends Challenge to the code segment, calculates resulting hash and returns it in the response. The application needs to ensure that returned hash coincides with the one stored in the hash library. _Command INS code:_ **0xF5** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Hash\_Name | 0x06 | byte\[5..9\] | Text name of hash function, supported value are ‘sha-256’, ‘sha-1’, ‘sha-224’, ‘sha-384’, ‘sha-512’, ‘crc-16’ | | Code\_Page\_Address | 0x40 | byte\[4\] | Value from 0 to ~3000. | | Code\_Page\_Count | 0x41 | byte\[2\] | Number of 32-byte pages to read: from 1 to 5, or 0 (only for Code\_Page\_Address=0)<br><br>When Code\_Page\_Address=0 and Code\_Page\_Count=0 then all Binary Code used to calculate hash | | Challenge | 0x16 | byte\[16\] | Additional challenge value from 1 to 10 | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Code\_Hash | 0x42 | byte\[32\] | Resulting hash SHA256(Firmware\_Version \| Challenge \| Code\_Page\_Address \| Code\_Page\_Count \| Binary Code) | ### 8.10 VERIFY\_CARD This command is used for card attestation. See details in Security section. The application shall call VERIFY\_CARD command to ensure the card has not been counterfeited. By using standard challenge-response scheme, the card proves possession of Card\_PrivateKey that corresponds to Card\_PublicKey returned by READ\_CARD command. _Command INS code:_ **0xF3** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | Challenge | 0x16 | byte\[16\] | Random challenge generated by host application | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Salt | 0x17 | byte\[16\] | Random salt generated by the card | | Card\_Signature | 0x04 | byte\[64\] | Hashed concatenated Challenge and Salt: SHA256(Challenge \| Salt) signed with Card\_PrivateKey | ### 8.11 VALIDATE\_CARD This is an optional command that the issuer can support if there is a real risk of mass counterfeiting by making multiple clones of a single card. This can be the case for transferrable Tangem cards that are almost never redeemed by users. The issuer has to have a back-end service storing and updating a counter value (Card\_Validation\_Counter) for each card (CID). This function should also be supported by the issuer’s application. The application may occasionally call VALIDATE\_CARD command to ensure that there’s only one card having this CID is circulating out there. VALIDATE\_CARD will increase COS internal Card\_Validation\_Counter by 1 and sign the new value with Card\_PrivateKey. Then the application should submit increased Card\_Validation\_Counter and its signature to issuer’s card validation back-end (server). The server should verify the signature and update Card\_Validation\_Counter value if previous value is less than the new one. If the server reveals that submitted Card\_Validation\_Counter value is less than previous value, then the card having this CID is deemed compromised and should not be accepted by the application. _Command INS code:_ **_0xF4_** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | PIN2 | 0x11 | byte\[32\] | Hashed user’s PIN2 code for signing and state-changing operations. See Security section for more details. | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Card\_Validation\_Counter | 0x18 | byte\[2\] | Internal validation counter | | Card\_Signature | 0x04 | byte\[64\] | Hashed Card\_Validation\_Counter signed with Card\_PrivateKey | ### 8.12 PURGE\_WALLET This command deletes all wallet data. If _Is\_Reusable_ flag is enabled during personalization, the card changes state to ‘Empty’ and a new wallet can be created by CREATE\_WALLET command. If _Is\_Reusable_ flag is disabled, the card switches to ‘Purged’ state. ‘Purged’ state is final, it makes the card useless. **Version 2.01 and later.** This command can be prohibited during the personalization stage by set flag Prohibit\_Purge\_Wallet in Settings\_Mask. _Command INS code:_ **0xFC** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | PIN2 | 0x11 | byte\[32\] | Hashed user’s PIN2 code for signing and state-changing operations. See Security section for more details. | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | Status | 0x02 | byte | Current status of the card<br><br>\[1 - Empty, 2 - Loaded, 3- Purged\] | ### 8.13 READ\_USER\_DATA VERSION 2.30 AND LATER This command returns two up to 512-byte User\_Data, User\_Protected\_Data and two counters User\_Counter and User\_Protected\_Counter fields. User\_Data and User\_ProtectedData are never changed or parsed by the executable code the Tangem COS. The App defines purpose of use, format and it's payload. For example, this field may contain cashed information from blockchain to accelerate preparing new transaction. User\_Counter and User\_ProtectedCounter are counters, that initial values can be set by App and increased on every signing of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use. For example, this fields may contain blockchain nonce value. _Command INS code:_ **_0xE1_** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | User\_Data | 0x2A | byte\[1..512\] | Data defined by user’s App | | User\_ProtectedData | 0x2B | byte\[1..512\] | Data defined by user’s App (confirmed by PIN2) | | User\_Counter | 0x2C | int\[4\] | Counter initialized by user’s App and increased on every signing of new transaction | | User\_ProtectedCounter | 0x2D | int\[4\] | Counter initialized by user’s App (confirmed by PIN2) and increased on every signing of new transaction | ### 8.14 WRITE\_USER\_DATA VERSION 2.30 AND LATER This command write some of User\_Data, User\_ProtectedData, User\_Counter and User\_ProtectedCounter fields. User\_Data and User\_ProtectedData are never changed or parsed by the executable code the Tangem COS. The App defines purpose of use, format and it's payload. For example, this field may contain cashed information from blockchain to accelerate preparing new transaction. User\_Counter and User\_ProtectedCounter are counters, that initial values can be set by App and increased on every signing of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use. For example, this fields may contain blockchain nonce value. Writing of User\_Counter and User\_Data protected only by PIN1. User\_ProtectedCounter and User\_ProtectedData additionaly need PIN2 to confirmation. _Command INS code:_ **0xE0** Parameters: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | | PIN1 | 0x10 | byte\[32\] | Hashed user’s PIN1 code to access the card. Default unhashed value: ‘000000’ | | PIN2 | 0x11 | byte\[32\] | Optional hashed user’s PIN2 code to confirm write User\_ProtectedData and User\_ProtectedCounter | | User\_Data | 0x2A | byte\[1..512\] | Optional data defined by user’s App | | User\_ProtectedData | 0x2B | byte\[1..512\] | Optional data defined by user’s App (PIN2 is mandatory) | | User\_Counter | 0x2C | int\[4\] | Optional new user counter value | | User\_Counter | 0x2D | int\[4\] | Optional new protected user counter value | Response: | | | | | | --- | --- | --- | --- | | Field | Tag | Type | Description | | CID | 0x01 | byte\[8\] | Unique Tangem card ID number | ~~9 Appendix A – Dynamic NDEF~~ --------------------------- ### 9.1 General description Card supports reading data in NDEF format in accordance with the standards of the NFC Forum: ● NFC Forum Type 4 Tag Operation Specification \[NFCForum-TS-Type-4-Tag\_2.0\] ● NFC Data Exchange Format (NDEF) Technical Specification \[NFCForum-TS-NDEF\_1.0\] NDEF contains three records: 1\. URI (value ‘tangem.com’) 2\. AAR (android application record, value ‘com.tangem.wallet’) – not used in iOS 3\. Dynamically generated record: ● Type – NFC Forum External type (value ‘tangem.com:wallet’) ● Content: o Status – two bytes (0x9000 – OK, 0x6A86 – card has PIN code set up, so TLV structure will not be given) o TLV data structure: ▪ CardID – unique car number ● Tag: 0x01 ● Length: 8 ▪ Firmware - card firmware version ● Tag: 0x80 ● Length: 4 – 10 ● UTF-8 string ▪ SettingsMask – card settings (see full manual) ● Tag: 0x0A ● Length: 2 ▪ Card\_Data – nested TLV structure with card properties ● Tag: 0x0C ● Length: 0 – 512 ● Format: o Batch\_ID – batch number ▪ Tag: 0x81 ▪ Length: 2 o Manufacture\_Date\_Time - manufacture date and time ▪ Tag: 0x82 ▪ Length: 4 o Issuer\_Name - card issuer name ▪ Tag: 0x83 ▪ UTF-8 string o Blockchain\_Name – the name of blockchain, which key card holds ▪ Tag: 0x84 ▪ UTF-8 string o Token\_Symbol – (optional) ERC20 token sybol (e.g., ‘SEED’) ▪ Tag: 0xA0 ▪ UTF-8 string o Token\_Contract\_Address – (optional) smart contract adress for ERC20 token ▪ Tag: 0xA1 ▪ UTF-8 string o Token\_Decimal – (optional) number of decimal places for ERC20 token (usually 18) ▪ Tag: 0xA2 ▪ 1 Byte o Manufacturer\_Signature – CID or (CID || Card\_PublicKey) signed with manufacturer’s secret key ▪ Tag: 0x86 ▪ Length: 64 ▪ Format \[R\[32\], S\[32\]\] for elliptical curve signature ▪ Card\_PublicKey – card public key ● Tag: 0x03 ● Length: 65 ▪ Wallet\_PublicKey - public key of the blockchain wallet ● Tag: 0x60 ● Length: 65 ● Format \[0x04, X\[32\], Y\[32\]\], elliptical curve secp256k1 ▪ MaxSignatures – initial number of allowed transaction signatures (set on personalization) ● Tag: 0x08 ● Length: 4 ▪ RemainingSignatures – remaining number of allowed transaction signatures ● Tag: 0x62 ● Length: 4 ▪ SignedHashes – number of hashes signed after personalization (there can be severeal hases in one transaction) ● Tag: 0x63 ● Length: 4 ▪ Challenge – first part of a message signed by card ● Tag: 0x16 ● Length: 16 ▪ Salt – second part of a message signed by card ● Tag: 0x17 ● Length: 16 ▪ Wallet\_Signature – \[Challenge, Salt\] SHA256 signature signed with Wallet\_PrivateKey ● Tag: 0x61 ● Length: 64 ● Format \[R\[32\],S\[32\]\] for elliptical curve signature ▪ Health – card state (0 – ОК, other value – card is damaged) ● Tag: 0x0F ● Length: 1 Note: If the card has no wallet (Status is set to ‘Empty’), then the record will contain only the following values: CardID, Firmware, Card\_Data, Card\_PublicKey, Health.  ### 9.2 Example (card with PIN set): * Record #1: URI record * Type Name Format: NFC Forum well-known type(1), * Short Record, * Type: "U" * Payload length: 11 bytes * Payload data: 01 74 61 6E 67 65 6D 2E 63 6F 6D (‘tangem.com’) * Record #2: Android Application record * Type Name Format: NFC Forum external type (4), * Short Record, * Type: "android.com:pkg" * Payload length: 17 bytes * Payload data: 63 6F 6D 2E 74 61 6E 67 65 6D 2E 77 61 6C 6C 65 74 (‘com.tangem.wallet’) * Record #3: NFC Forum external type record * Type Name Format: NFC Forum external type (4) * Short Record * Type: "tangem.com:wallet" * Payload length: 2 bytes * Payload data: 6A 86 ### 9.3 Example (before wallet creation): * Record #1: URI record * Type Name Format: NFC Forum well-known type(1), * Short Record, * type: "U" *

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully