Flipper Zero Transfer NFC File Version 3 to File Version 4

I had some small talk with @b1u3n4zgu1 about converting NFC files.
Due the refactoring of NFC within the Flipper0, a new format was introduced. Here you have a python script to do the conversions for you.
I removed the privacy key password, cause I could imagine this will cause some trouble beeing online.
Just ask me in Telegram Chat or use the Flipper to see it :).

import os
import sys

def update_file_content(lines):
  """
  Aktualisierung des Dateiinhalts mit den übergebenen Werten.

  Args:
    lines: Liste der Textzeilen der Datei.

  Returns:
    Liste der aktualisierten Textzeilen.
  """

  # Suchen und Ersetzen der Version
  for i, line in enumerate(lines):
    if line.startswith("Version:"):
      lines[i] = line.replace("Version: 3", "Version: 4")

  # Suchen und Ersetzen des Gerätetyps
  for i, line in enumerate(lines):
    if line.startswith("Device type:"):
      lines[i] = line.replace("Device type: ISO15693", "Device type: SLIX-L")

  # Einfügen der zusätzlichen Werte
  lines.append("Password Privacy: 00 00 00 00\n")
  lines.append("Password Destroy: FF FF FF FF\n")
  lines.append("Password EAS: 00 00 00 00\n")
  lines.append("Lock EAS: false\n")

  return lines

def main():
  """
  Hauptfunktion zum Bearbeiten und Speichern der Datei.
  """

  if len(sys.argv) != 2:
    print("Fehler: Falsche Anzahl an Argumenten.")
    print("Aufruf: python flipper_nfc_editor.py <dateiname>")
    return

  filepath = sys.argv[1]

  # Extrahieren des Dateinamens ohne Endung
  filename, _ = os.path.splitext(filepath)

  # Lesen der Datei
  with open(filepath, "r") as f:
    lines = f.readlines()

  # Aktualisieren des Dateiinhalts
  lines = update_file_content(lines)

  # Speichern der Datei mit neuer Endung
  new_filepath = f"{filename}.v4.nfc"
  with open(new_filepath, "w") as f:
    f.writelines(lines)

  print(f"Datei '{new_filepath}' erfolgreich erstellt.")


if __name__ == "__main__":
  main()

For Windows Users, but untested:

param(
  [Parameter(Mandatory=$true)]
  [string] $FilePath
)

# Extrahieren des Dateinamens ohne Endung
$Filename = $FilePath.Split('.\')[-1].Split('.')[0]

# Lesen des Dateiinhalts
$FileContent = Get-Content -Path $FilePath

# Ersetzen der Version
$FileContent = $FileContent -Replace 'Version: 3', 'Version: 4'

# Ersetzen des Gerätetyps
$FileContent = $FileContent -Replace 'Device type: ISO15693', 'Device type: SLIX-L'

# Hinzufügen der zusätzlichen Werte
$FileContent += "nPassword Privacy: 00 00 00 00n"
$FileContent += "nPassword Destroy: FF FF FF FFn"
$FileContent += "nPassword EAS: 00 00 00 00n"
$FileContent += "nLock EAS: falsen"

# Speichern der Datei mit neuer Endung
Set-Content -Path "$Filename.v4.nfc" -Value $FileContent

Write-Host "Datei '$Filename.v4.nfc' erfolgreich erstellt."

Thanks @Wurst420 for starting this, after a short talk with @g3gg0 here are finaly scripts to convert old V3 Flipper Zero NFC Files into the new V4 Format, this will allow you to emulate you existing .nfc files with the lastest Firmware i have tested the Emulation with the Xtreme Dev 18.02.2024

Hint:
after the NFC Refactoring the Flipper OFW Dev Team changed the Emulation to an 5 min. Limit, this makes it impossible to listen to an complete Audio without restart the emulation, i allready created an feature request to change this or add an option for endless emulation NFC Emulation Time Limit · Issue #3460 · flipperdevices/flipperzero-firmware · GitHub

I created the scripts with the help of ChatGPT.

The scripts are able convert a single file

fz-nfc-convert.sh -s flipper.nfc

or an folder of .nfc files

fz-nfc-convert.sh -f \nfc

the output file is allways within the same location as the input file, filename also stays the same *.nfc but with an added “_v4” so it will look like *_v4.nfc

fz-nfc-convert.sh for thoose who run an Linuy or Mac Device (tested on Ubuntu 23.04)

#!/bin/bash

while getopts ":sf:" option; do
  case $option in
    s)
      single_file=true
      ;;
    f)
      folder_path="$OPTARG"
      folder_mode=true
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

shift $((OPTIND - 1))

# Function to convert a single file
convert_file() {
  local input_file="$1"
  local output_file="${input_file%.nfc}_v4.nfc"

  version=$(awk '/Version:/ {print $2}' "$input_file")

  if [[ "$version" != "3" ]]; then
    echo "Skipping conversion for $input_file (Version: $version)"
    return
  fi

  uid=$(grep 'UID:' "$input_file" | sed 's/^[ \t]*UID: //')
  data=$(grep 'Data Content:' "$input_file" | sed 's/^[ \t]*Data Content: //')

  cat <<EOF > "$output_file"
Filetype: Flipper NFC device
Version: 4
Device type: SLIX
# UID is common for all formats
UID: $uid
# ISO15693-3 specific data
DSFID: 00
AFI: 00
IC Reference: 03
Lock DSFID: false
Lock AFI: false
# Number of memory blocks, valid range = 1..256
Block Count: 8
# Size of a single memory block, valid range = 01...20 (hex)
Block Size: 04
Data Content: $data
# Block Security Status: 01 = locked, 00 = not locked
Security Status: 00 00 00 00 00 00 00 00
# SLIX specific data
# Passwords are optional. If a password is omitted, a default value will be used
Password Privacy: 7F FD 6E 5B
Password Destroy: FF FF FF FF
Password EAS: 00 00 00 00
Privacy Mode: true
# SLIX Lock Bits
Lock EAS: false
EOF

  echo "Conversion completed. Output written to $output_file"
}

# Handle single file mode
if [ "$single_file" = true ]; then
  if [ "$#" -ne 1 ]; then
    echo "Usage: $0 -s input_file"
    exit 1
  fi
  convert_file "$1"
fi

# Handle folder mode
if [ "$folder_mode" = true ]; then
  if [ ! -d "$folder_path" ]; then
    echo "Invalid folder path: $folder_path"
    exit 1
  fi

  for input_file in "$folder_path"/*.nfc; do
    if [ -f "$input_file" ]; then
      convert_file "$input_file"
    fi
  done
fi

fz-nfc-convert.bat for thoose who uses Windows Devices

t@echo off
setlocal enabledelayedexpansion

:parse_args
set "single_file="
set "folder_mode="
set "folder_path="

:parse_loop
if "%~1" == "" goto main
if /i "%~1" == "-s" (
    set "single_file=true"
    shift /1
    goto parse_loop
)
if /i "%~1" == "-f" (
    set "folder_mode=true"
    set "folder_path=%~2"
    shift /2
    goto parse_loop
)
goto invalid_arg

:main
if not defined single_file if not defined folder_mode goto show_help

:process_files
if defined single_file (
    call :convert_file "%~1"
) else (
    if not defined folder_path goto show_help
    for %%I in ("%folder_path%\*.nfc") do (
        call :convert_file "%%I"
    )
)

goto end

:convert_file
set "input_file=%~1"
set "output_file=!input_file:.nfc=_v4.nfc!"

for /f "tokens=2 delims=: " %%V in ('findstr /i "Version:" "%input_file%"') do set "version=%%V"

if /i not "!version!" == "3" (
    echo Skipping conversion for %input_file% (Version: !version!)
    goto :eof
)

for /f "tokens=2 delims=: " %%U in ('findstr /i "UID:" "%input_file%"') do set "uid=%%U"
for /f "tokens=3 delims=: " %%D in ('findstr /i "Data Content:" "%input_file%"') do set "data=%%D"

(
    echo Filetype: Flipper NFC device
    echo Version: 4
    echo Device type: SLIX
    echo # UID is common for all formats
    echo UID: !uid!
    echo # ISO15693-3 specific data
    echo DSFID: 00
    echo AFI: 00
    echo IC Reference: 03
    echo Lock DSFID: false
    echo Lock AFI: false
    echo # Number of memory blocks, valid range = 1..256
    echo Block Count: 8
    echo # Size of a single memory block, valid range = 01...20 (hex)
    echo Block Size: 04
    echo Data Content: !data!
    echo # Block Security Status: 01 = locked, 00 = not locked
    echo Security Status: 00 00 00 00 00 00 00 00
    echo # SLIX specific data
    echo # Passwords are optional. If a password is omitted, a default value will be used
    echo Password Privacy: 7F FD 6E 5B
    echo Password Destroy: FF FF FF FF
    echo Password EAS: 00 00 00 00
    echo Privacy Mode: true
    echo # SLIX Lock Bits
    echo Lock EAS: false
) > "%output_file%"

echo Conversion completed. Output written to %output_file%
goto :eof

:show_help
echo Usage: %~nx0 [-s input_file | -f folder_path]
goto end

:invalid_arg
echo Invalid argument: %1
goto :eof

:end
endlocal

fz-nfc-convert.py for thoose who want to use python ony universal maschines

import argparse
import os

def convert_file(input_file):
    output_file = input_file.replace(".nfc", "_v4.nfc")

    with open(input_file, 'r') as infile, open(output_file, 'w') as outfile:
        version = None
        uid = None
        data = None

        for line in infile:
            if "Version:" in line:
                version = line.split()[1]
            elif "UID:" in line:
                uid = line.split()[1]
            elif "Data Content:" in line:
                data = line.split()[2]

        if version != "3":
            print(f"Skipping conversion for {input_file} (Version: {version})")
            return

        outfile.write(f"""Filetype: Flipper NFC device
Version: 4
Device type: SLIX
# UID is common for all formats
UID: {uid}
# ISO15693-3 specific data
DSFID: 00
AFI: 00
IC Reference: 03
Lock DSFID: false
Lock AFI: false
# Number of memory blocks, valid range = 1..256
Block Count: 8
# Size of a single memory block, valid range = 01...20 (hex)
Block Size: 04
Data Content: {data}
# Block Security Status: 01 = locked, 00 = not locked
Security Status: 00 00 00 00 00 00 00 00
# SLIX specific data
# Passwords are optional. If a password is omitted, a default value will be used
Password Privacy: 7F FD 6E 5B
Password Destroy: FF FF FF FF
Password EAS: 00 00 00 00
Privacy Mode: true
# SLIX Lock Bits
Lock EAS: false
""")

    print(f"Conversion completed. Output written to {output_file}")

def convert_folder(folder_path):
    for filename in os.listdir(folder_path):
        if filename.endswith(".nfc"):
            convert_file(os.path.join(folder_path, filename))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Convert Flipper NFC files from version 3 to version 4")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("-s", "--single", help="Convert a single file", metavar="input_file")
    group.add_argument("-f", "--folder", help="Convert all files in a folder", metavar="folder_path")

    args = parser.parse_args()

    if args.single:
        convert_file(args.single)
    elif args.folder:
        convert_folder(args.folder)

for those who having issues to emulate “Version 4” that are created usinf the FlipperZero and are not converted using the scripts above, here is an yet untested script that changes the “Privacy Passsword” and the “Privacy Mode”

the script should only edit “Version 4” .NFC Files

.sh script

#!/bin/bash

# Function to check and update values in a Version 4 .nfc file
check_and_update_values() {
  local input_file="$1"
  local output_file="${input_file%.nfc}_updated.nfc"

  # Check if the file is a Version 4 .nfc file
  if ! grep -q "Version: 4" "$input_file"; then
    echo "Skipping file $input_file as it is not a Version 4 .nfc file."
    return
  fi

  privacy_password=$(grep 'Password Privacy:' "$input_file" | awk '{print $3}')
  privacy_mode=$(grep 'Privacy Mode:' "$input_file" | awk '{print $3}')

  # Check and update Privacy Password
  if [ "$privacy_password" != "7F FD 6E 5B" ]; then
    sed -i 's/Password Privacy: .*/Password Privacy: 7F FD 6E 5B/' "$input_file"
    echo "Privacy Password updated in $input_file"
  fi

  # Check and update Privacy Mode
  if [ "$privacy_mode" != "true" ]; then
    sed -i 's/Privacy Mode: .*/Privacy Mode: true/' "$input_file"
    echo "Privacy Mode updated in $input_file"
  fi
}

# Handle single file mode
if [ "$#" -eq 1 ]; then
  check_and_update_values "$1"
else
  echo "Usage: $0 input_file"
  exit 1
fi

.bat file

@echo off
setlocal enabledelayedexpansion

:parse_args
set "single_file="
set "folder_mode="
set "folder_path="

:parse_loop
if "%~1" == "" goto main
if /i "%~1" == "-f" (
    set "folder_mode=true"
    set "folder_path=%~2"
    shift /2
    goto parse_loop
)
goto invalid_arg

:main
if not defined folder_mode goto show_help

:process_files
if defined folder_mode (
    if not defined folder_path goto show_help
    for %%I in ("%folder_path%\*.nfc") do (
        call :check_and_update "%%I"
    )
)

goto end

:check_and_update
set "input_file=%~1"

rem Check if the file is a Version 4 .nfc file
findstr /i "Version: 4" "%input_file%" >nul
if errorlevel 1 (
    echo Skipping file %input_file% as it is not a Version 4 .nfc file.
    goto :eof
)

for /f "tokens=3 delims=: " %%P in ('findstr /i "Password Privacy:" "%input_file%"') do set "privacy_password=%%P"
for /f "tokens=3 delims=: " %%M in ('findstr /i "Privacy Mode:" "%input_file%"') do set "privacy_mode=%%M"

rem Check and update Privacy Password
if not "!privacy_password!" == "7F FD 6E 5B" (
    (
        echo Password Privacy: 7F FD 6E 5B
        echo !privacy_mode!
    ) > "%input_file%.tmp"
    move /y "%input_file%.tmp" "%input_file%" >nul
    echo Privacy Password updated in %input_file%
)

rem Check and update Privacy Mode
if not "!privacy_mode!" == "true" (
    (
        echo !privacy_password!
        echo Privacy Mode: true
    ) > "%input_file%.tmp"
    move /y "%input_file%.tmp" "%input_file%" >nul
    echo Privacy Mode updated in %input_file%
)

echo Check and update completed for %input_file%
goto :eof

:show_help
echo Usage: %~nx0 -f folder_path
goto end

:invalid_arg
echo Invalid argument: %1
goto :eof

:end
endlocal

Python script

import os
import sys

def check_and_update_values(input_file):
    output_file = f"{input_file}_updated.nfc"

    # Check if the file is a Version 4 .nfc file
    with open(input_file, 'r') as infile:
        if "Version: 4" not in infile.read():
            print(f"Skipping file {input_file} as it is not a Version 4 .nfc file.")
            return

    with open(input_file, 'r') as infile, open(output_file, 'w') as outfile:
        privacy_password_updated = False
        privacy_mode_updated = False

        for line in infile:
            if "Password Privacy:" in line and not privacy_password_updated:
                outfile.write("Password Privacy: 7F FD 6E 5B\n")
                privacy_password_updated = True
            elif "Privacy Mode:" in line and not privacy_mode_updated:
                outfile.write("Privacy Mode: true\n")
                privacy_mode_updated = True
            else:
                outfile.write(line)

    if privacy_password_updated:
        print(f"Privacy Password updated in {input_file}")

    if privacy_mode_updated:
        print(f"Privacy Mode updated in {input_file}")

if __name__ == "__main__":
    if len(sys.argv) != 3 or sys.argv[1].lower() != "-f":
        print("Usage: python script.py -f folder_path")
        sys.exit(1)

    folder_path = sys.argv[2]

    for filename in os.listdir(folder_path):
        if filename.lower().endswith(".nfc"):
            check_and_update_values(os.path.join(folder_path, filename))

the scripts should also work for single files and folders

here is an yet ntested script that changes the “Privacy Passsword” and the “Privacy Mode”

As mentioned, I removed the password for security reasons. I don’t want Boxine shutting down this forum cause of spreading their password, like AACS or the PS3 keys George Hotz released (–> Illegal number - Wikipedia)

I talked to @g3gg0 and @Gambrius befor i posted my Scripts, they told me the PW ist not a secret, thats why i included IT into my Scripts here