Koen Schoffner
Koen Schoffner

Reputation: 1

Setting Password protection for NFC Tag ISO 14443

I am trying to create a feature for an app where we store text information on an NFC tag. The information is started as text and is ~128 bytes. The issue is that I want to add password protection to the tag so that other people cannot write to it. for reference, the tag I am using is the one specified in this document: https://resourcewebsite.singoo.cc/15307900505930426/en/pdf/1670211742605/FM11NT021_sds_eng.pdf

I am also using react-native and react-native-nfc-manger for this project.

Currently, when I use the setPassword function, it seems like the password and pack commands work, but then I get a "Connection loss" to the tag before it seems the auth0 wirte is completed.

When I go to write to the tag, the pack comes back as [0, 0] inn either the writeNdefWithPass or the authenticatePassword functions.

Does anyone see where I might be going wrong? I'm not sure if the messages are formatted correctly or if I am writing to the right addresses. the code is below:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 */



// important link: https://www.youtube.com/watch?v=rAS-DvNUFck&t=2591s
import React, { useEffect } from 'react';
import type {PropsWithChildren} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  TextInput,
  Button,
  Alert,
  TouchableOpacity,
  Platform,
} from 'react-native';

import NfcManager, {NfcTech, NfcEvents, Ndef} from 'react-native-nfc-manager';
// Pre-step, call this before any NFC operations
NfcManager.start();


function App(): React.JSX.Element {
  const [inputs, setInputs] = React.useState({
    serialnumber: '',
    codeVersion: '',
    Date: '',
    setting1: '',
    setting2: '',
    setting3: '',
    setting4: '',

  });

  const[outputs , setOutputs] = React.useState({
    serialnumber: '',
    codeVersion: '',
    Date: '',
    setting1: '',
    setting2: '',
    setting3: '',
    setting4: '',
  });

  const showReadAlert = () => {
    Alert.alert(
      "NFC Action Required",
      "Please bring your phone near the receiver and press ok to read the Values from the receiver",
      [
        { text: "Cancel", style: "cancel" },
        { text: "OK", onPress: readNdef }
      ]
    );
  };

  const showWriteAlert = () => {
    Alert.alert(
      "NFC Action Required",
      "Please bring your phone near the receiver and press ok to write the Values to the receiver",
      [
        { text: "Cancel", style: "cancel" },
        { text: "OK", onPress: writeNdef }
      ]
    );
  };

  useEffect(() => {
    async function checkNfc(){
      const supported = await NfcManager.isSupported();
      console.log('NFC Supported:', supported);
      if (supported) {
        await NfcManager.start();
        console.log('NFC started');
      }
    }
    checkNfc();
  }, []);

  useEffect(() =>{
    console.log(outputs)

  }, [outputs])

  const getInputString = () =>{
    console.log("Getting input string")
    return 'SN:' + inputs.serialnumber + ', ' + 'RX:' + inputs.codeVersion + ', ' + 'Date:' + inputs.Date + ', ' + 'S1:' + inputs.setting1 + ', ' + 'S2:' + inputs.setting2 + ', ' + 'S3:' + inputs.setting3 + ', ' + 'S4:' + inputs.setting4;
  }

  const proccessPayload = (payload) => {
    console.log("Processing payload")
    let payloadString = Ndef.text.decodePayload(payload);
    let payloadArray = payloadString.split(', ');
    let serialnumber = payloadArray[0].split(':');
    let codeVersion = payloadArray[1].split(':');
    let Date = payloadArray[2].split(':');
    let setting1 = payloadArray[3].split(':');
    let setting2 = payloadArray[4].split(':');
    let setting3 = payloadArray[5].split(':');
    let setting4 = payloadArray[6].split(':');
    setOutputs({
      serialnumber: serialnumber[1],
      codeVersion: codeVersion[1],
      Date: Date[1],
      setting1: setting1[1],
      setting2: setting2[1],
      setting3: setting3[1],
      setting4: setting4[1],
    });
    console.log(outputs)
  }

  async function readNdef() {
    console.log('readNdef');
    
    try {
      // register for the NFC tag with NDEF in it
      await NfcManager.requestTechnology(NfcTech.Ndef);
      // the resolved tag object will contain `ndefMessage` property
      const tag = await NfcManager.getTag();
      console.warn('Tag found', tag);
      proccessPayload(tag.ndefMessage[0].payload);
    } catch (ex) {
      console.warn('Oops!', ex);
    } finally {
      // stop the nfc scanning
      NfcManager.cancelTechnologyRequest();
    }
  }

  async function writeNdef() {
    console.log('writeNdef');
    let result = false;
  
    try {
      // STEP 1
      await NfcManager.requestTechnology(NfcTech.Ndef);
  
      const bytes = Ndef.encodeMessage([Ndef.textRecord(getInputString())]);
  
      if (bytes) {
        await NfcManager.ndefHandler // STEP 2
          .writeNdefMessage(bytes); // STEP 3
        result = true;
      }
    } catch (ex) {
      console.warn(ex);
    } finally {
      // STEP 4
      NfcManager.cancelTechnologyRequest();
    }
  
    return result;
  }

  async function writeNdefWithPass() {
    console.log('writeNdefwithpass');
    let result = false;
  
    try {
      // STEP 1: Request NFC technology (NfcA or IsoDep)
      await NfcManager.requestTechnology(NfcTech.NfcA);  // Use NfcA for FM11NT021
      
      const password = [0x74, 0x65, 0x73, 0x74];  // Your 4-byte password
      console.log("Authenticating with password...");
      
      // Build the PWD_AUTH command (0x1B)
      const pwdAuthCommand = [
        0x1B,              // Command code for PWD_AUTH
        ...password,       // 4-byte password
      ];
  
      // Send the PWD_AUTH command
      const response = await NfcManager.nfcAHandler.transceive(pwdAuthCommand);
      console.log("PWD_AUTH Response:", response);
  
      // Extract the PACK (first 2 bytes of the response)
      const packResponse = response.slice(0, 2);
      const expectedPack = [0x67, 0x6f];  // Replace with your actual stored PACK value
  
      if (JSON.stringify(packResponse) === JSON.stringify(expectedPack)) {
        console.log('Password authenticated successfully. Writing data...');
  
        // STEP 2: Write data to the NFC tag
        const bytes = Ndef.encodeMessage([Ndef.textRecord(getInputString())]);
        if (bytes) {
          await NfcManager.ndefHandler.writeNdefMessage(bytes);  // STEP 3: Write NDEF data
          result = true;
          console.log("Data written successfully.");
        }
      } else {
        console.log('Password authentication failed. Writing aborted.');
      }
    } catch (ex) {
      console.warn('Error:', ex);
    } finally {
      // STEP 4: Cancel NFC technology request
      NfcManager.cancelTechnologyRequest();
    }
  
    return result;
  }

  // 74 65 73 74
  async function setPassword() {
    try {
      // STEP 1: Request NFC technology
      // STEP 2: send PWD 
      await NfcManager.requestTechnology(NfcTech.Ndef);
      // const isoDep = await NfcManager.getTag();
      const password = [0x74, 0x65, 0x73, 0x74]; // Your 4-byte password
      const pack = [0x67, 0x6f]; // Your 2-byte PACK value
      const auth0 = 0x04;  // Protect starting from page 4

      const writePasswordCMD = [
        0xA2,  // WRITE command
        0x2B,  // PWD memory address
        ...password,
      ]

      const writePackCMD = [
        0xA2,  // WRITE command
        0x2C,  // PACK memory address
        ...pack,
      ]

      const writeAuth0CMD = [
        0xA2,  // WRITE command
        0x29,  // AUTH0 memory address
        auth0, 0x00, 0x00, 0x00 // Lock all pages starting from page 4
      ]

      await NfcManager.nfcAHandler.transceive(writePasswordCMD);
      await NfcManager.nfcAHandler.transceive(writePackCMD);
      await NfcManager.nfcAHandler.transceive(writeAuth0CMD);

    } catch (ex) {
      console.warn(ex);
    } finally {
      // STEP 3: Cancel the NFC technology request
      NfcManager.cancelTechnologyRequest();
    }
  }

  async function authenticatePassword() {
    try {
      // Request NFC technology (IsoDep for FM11NT021)
      await NfcManager.requestTechnology(NfcTech.Ndef);
  
      const isoDep = await NfcManager.getTag();
      const password = [0x74, 0x65, 0x73, 0x74]; // Your 4-byte password
      console.log("auth password 1")
      // Build the PWD_AUTH command (0x1B)
      const pwdAuthCommand = [
        0x1B,             // Command code for PWD_AUTH
        ...password,      // 4-byte password
      ];
  
      // Send the command and get the response
      const response = await NfcManager.nfcAHandler.transceive(pwdAuthCommand);
      console.log("auth password 1")
      console.log('PWD_AUTH Response:', response);
  
      // Compare with the PACK to confirm successful authentication
      const PACK = response.slice(0, 2); // Should match the stored PACK
  
    } catch (ex) {
      console.warn(ex);
    } finally {
      // Close the connection
      NfcManager.cancelTechnologyRequest();
    }
  }
  

  return (
  <ScrollView>
  <View style={styles.container}>
    <TextInput
      style={styles.input}
      placeholder="Serial Number"
      value={inputs.serialnumber}
      maxLength={8}
      onChangeText={(text) => setInputs({ ...inputs, serialnumber: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Code Version"
      value={inputs.codeVersion}
      maxLength={4}
      onChangeText={(text) => setInputs({ ...inputs, codeVersion: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Date"
      value={inputs.Date}
      maxLength={10}
      onChangeText={(text) => setInputs({ ...inputs, Date: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Setting 1"
      value={inputs.setting1}
      maxLength={2}
      onChangeText={(text) => setInputs({ ...inputs, setting1: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Setting 2"
      value={inputs.setting2}
      maxLength={2}
      onChangeText={(text) => setInputs({ ...inputs, setting2: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Setting 3"
      value={inputs.setting3}
      maxLength={2}
      onChangeText={(text) => setInputs({ ...inputs, setting3: text })}
    />
    <TextInput
      style={styles.input}
      placeholder="Setting 4"
      value={inputs.setting4}
      maxLength={2}
      onChangeText={(text) => setInputs({ ...inputs, setting4: text })}
    />
    <TouchableOpacity style={styles.button} onPress={Platform.OS == 'android' ? showWriteAlert :writeNdef}>
          <Text style={styles.buttonText}>Write to NFC tag</Text>
    </TouchableOpacity>
    <TouchableOpacity style={styles.button} onPress={Platform.OS == 'android' ? showWriteAlert :writeNdefWithPass}>
          <Text style={styles.buttonText}>Write to NFC tag with pass</Text>
    </TouchableOpacity>
    <TouchableOpacity style={styles.button} onPress={Platform.OS == 'android' ? showReadAlert :readNdef}>
          <Text style={styles.buttonText}>Read NFC Tag</Text>
    </TouchableOpacity>
    <TouchableOpacity style={styles.button} onPress={Platform.OS == 'android' ? setPassword : setPassword}>
          <Text style={styles.buttonText}>Set Password (test)</Text>
    </TouchableOpacity>
    <TouchableOpacity style={styles.button} onPress={Platform.OS == 'android' ? authenticatePassword : authenticatePassword}>
          <Text style={styles.buttonText}>Test Password (test)</Text>
    </TouchableOpacity> 
    
    <View>
      <View style={styles.displayBox}>
        <Text style = {styles.outTitle}> last Read Output</Text>
        <Text>Serial Number: {outputs.serialnumber}</Text>
        <Text>Code Version: {outputs.codeVersion}</Text>
        <Text>Date: {outputs.Date}</Text>
        <Text>Setting 1: {outputs.setting1}</Text>
        <Text>Setting 2: {outputs.setting2}</Text>
        <Text>Setting 3: {outputs.setting3}</Text>
        <Text>Setting 4: {outputs.setting4}</Text>
      </View>
    </View>
  </View>
  </ScrollView>
  );
}


export default App;


const styles = StyleSheet.create({
  container: {
    marginTop:10,
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 16,
    backgroundColor: 'black',
  },
  input: {
    color: 'white',
    height: 40,
    borderColor: '#ccc',
    borderWidth: 1,
    borderRadius: 4,
    marginBottom: 12,
    paddingHorizontal: 8,
    width: '80%',
    backgroundColor: 'red',
  },
  button: {
    backgroundColor: '#007BFF',
    padding: 10,
    borderRadius: 5,
    marginTop: 10,
    width: '80%',
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
  },
  wrapper: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor:'blue',
    width: '80%',
    height: '20%',
  },
  displayBox:{
    backgroundColor: 'green',
    padding: 10,
    borderRadius: 5,
    marginTop: 10,
    marginBottom:30,
    alignItems: 'center',
  },
  outTitle:{
    color: 'white',
    fontSize: 20,
    fontWeight: 'bold',
    margin: 20
  }
});

Upvotes: 0

Views: 58

Answers (0)

Related Questions