Reputation: 1
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