Table of Contents

Modbus RTU crittografato

Questa pagina descrive come integrare un motore lineare integrato NILAB (famiglia NLi / GDi) in un controller di macchina basato su PLC usando il protocollo Modbus RTU crittografato NILAB.

Il livello di crittografia opera in modo trasparente sopra il Modbus RTU standard su RS-485. Non sono richieste modifiche al cablaggio fisico o alla mappa dei registri Modbus RTU standard. I drive con crittografia disabilitata comunicano come slave Modbus RTU standard e sono completamente retrocompatibili con qualsiasi master Modbus generico.

L'implementazione crittografica è fornita come libreria chiusa, pre-compilata per ogni ambiente di sviluppo supportato (CODESYS, C/C++, .NET). L'algoritmo interno è proprietario di NILAB GmbH. La libreria è disponibile per gli integratori nell'ambito di un accordo di partner tecnologico NILAB — contatta NILAB per l'accesso.


Se la crittografia è abilitata sul drive, il drive risponderà solo a frame crittografati. Qualsiasi richiesta Modbus in chiaro (FC3, FC6, FC16) sarà scartata silenziosamente. Devi usare la libreria di crittografia NILAB per comunicare con un drive con crittografia abilitata.

1. Panoramica del concetto e del protocollo

1.1 Cosa fornisce il livello di crittografia

Il livello Modbus RTU crittografato NILAB aggiunge tre proprietà di sicurezza al protocollo Modbus RTU standard:

Voce
Autenticità — ogni frame porta un tag crittografico. Il drive verifica questo tag prima di elaborare qualsiasi richiesta. I frame falsificati, corrotti o ripetuti vengono scartati silenziosamente senza alcuna risposta.
Riservatezza — la PDU Modbus (codice funzione e dati dei registri) è crittografata. Un osservatore sul bus RS-485 non può leggere i valori dei registri o i setpoint.
Anti-replay — un contatore di frame monotono incorporato in ogni frame impedisce che un frame valido catturato venga reiniettato in un momento successivo.

La protezione è bidirezionale: sia la richiesta master→drive che la risposta drive→master sono crittografate e autenticate.

1.2 Chiave

Ogni drive NILAB è dotato in fabbrica di una chiave AES 128-bit univoca, memorizzata in memoria flash protetta. La chiave è legata al numero di serie del drive nel database chiavi NILAB.

Per ottenere la chiave per un drive specifico, contatta NILAB GmbH con il numero di serie del drive. La chiave è consegnata come stringa esadecimale di 32 caratteri, ad esempio:

1D23586E43A218620EC5C7486274CAD0

Questa chiave deve essere trattata come segreta. Deve essere memorizzata in memoria protetta sul lato PLC e non deve mai essere trasmessa sul bus o scritta nei log di sistema.

1.3 Formato del frame crittografato

Il frame crittografato sostituisce il codice funzione e la PDU Modbus standard con un wrapper a struttura fissa identificato dal codice funzione 0x65:

Modbus RTU standard (in chiaro):
[ Node ID (1) ][ FC (1) ][ PDU (N) ][ CRC16 (2) ]

Modbus RTU crittografato NILAB:
[ Node ID (1) ][ 0x65 (1) ][ Counter (4) ][ Ciphertext (N) ][ Tag (8) ][ CRC16 (2) ]
CampoDimensione (byte)Descrizione
Node ID1Indirizzo slave Modbus, invariato
0x651Marcatore PDU crittografata NILAB
Counter4Contatore frame, big-endian, strettamente crescente
CiphertextNPDU Modbus crittografata (stesso contenuto della PDU in chiaro)
Tag8Tag di autenticazione crittografico su Counter + Ciphertext
CRC162CRC16 Modbus standard su tutti i byte precedenti

L'overhead aggiunto dal wrapper di crittografia è 12 byte per frame (4 counter + 8 tag) rispetto al frame in chiaro equivalente.

Il CRC16 usa il polinomio Modbus standard e l'ordine dei byte (byte basso per primo) ed è calcolato sull'intero frame includendo Node ID, codice funzione 0x65, counter, ciphertext e tag — esattamente come nel Modbus RTU standard.

1.4 Contatore frame

Il contatore frame è un intero senza segno a 32 bit, trasmesso big-endian (byte più significativo per primo). È indipendente per direzione:

Voce
Il master (PLC) incrementa il suo contatore TX con ogni richiesta che invia.
Il drive tiene traccia dell'ultimo contatore TX master accettato e rifiuta qualsiasi frame con un contatore che non sia strettamente maggiore dell'ultimo valore accettato.
Il drive usa il proprio contatore TX per le risposte crittografate; il master tiene traccia di questo per rilevare risposte replay.

I contatori iniziano a 0 alla prima messa in servizio. Devono essere salvati in memoria non volatile e ripristinati all'avvio — vedi Sezione 5.

1.5 Riepilogo del comportamento del drive

Stato del driveFC3/FC6 in chiaro dal masterFC 0x65 crittografato dal master (chiave corretta)Sync broadcast (FC 0x80, node 0x00)
Crittografia disabilitata (default di fabbrica)Accettato, risposta normaleNon compreso, risposta eccezioneSempre accettato
Crittografia abilitata Scartato silenziosamenteAccettato, risposta crittografataSempre accettato

2. Come iniziare

2.1 Prerequisiti

Voce
Un motore lineare integrato NLi o GDi NILAB con firmware di crittografia (chiedi a NILAB la versione di firmware che supporta la crittografia).
La chiave AES di 16 byte per il drive specifico, ottenuta da NILAB (vedi Sezione 1.2).
La libreria crypto NILAB per il tuo ambiente di sviluppo (vedi Sezione 3).
Cablaggio RS-485: bus Modbus RTU standard, 2 fili, con corretta terminazione.

2.2 Parametri di comunicazione

Il protocollo crittografato usa gli stessi parametri seriali del Modbus RTU NILAB standard:

ParametroValore
Baud rate115200 bps (default)
Data bits8
ParityNessuna
Stop bits1
ProtocolloModbus RTU
Node IDConfigurato sul drive (default: 1)

2.3 Dimensioni dei frame per i calcoli di timing

La dimensione totale del frame dipende dalla dimensione della PDU interna. Per le operazioni più comuni:

OperazionePDU interna (byte)Frame crittografato totale (byte)
FC6 scrittura, 1 registro51+1+4+5+8+2 = 21
FC3 lettura, 1 registro5 (richiesta)1+1+4+5+8+2 = 21
FC3 lettura, 1 registro4 (risposta)1+1+4+4+8+2 = 20
FC3 lettura, N registri3+2N (risposta)1+1+4+(3+2N)+8+2 = 19+2N

Usa questi valori per impostare timeout di ricezione seriale appropriati sul lato PLC.


3. Libreria crypto NILAB

NILAB fornisce una libreria chiusa, pre-compilata per ogni ambiente di sviluppo PLC supportato. La libreria espone un'API minimale e ben definita (vedi Sezione 4) e gestisce tutte le operazioni crittografiche internamente. Non è richiesta conoscenza dell'algoritmo sottostante per l'integrazione.

3.2 Ottenere la libreria

La libreria è distribuita nell'ambito di un accordo di partner tecnologico NILAB. Per richiedere l'accesso:

Voce
Contatta NILAB GmbH con oggetto “Encrypted Modbus Library Request”
Specifica il tuo ambiente di sviluppo (vedi tabella sopra)
Fornisci i numeri di serie dei drive NILAB che stai integrando

NILAB fornirà il pacchetto libreria insieme alle chiavi del drive corrispondenti.


4. API della libreria

Tutte le varianti della libreria espongono la stessa API logica, adattata alle convenzioni dell'ambiente di destinazione. La seguente descrizione usa notazione pseudocodice.

4.1 Inizializzazione

\
NILAB_Init(ctx, key[16], tx_counter, rx_counter)\

Inizializza un contesto crypto per una connessione drive.

ParametroTipoDescrizione
ctxhandle opacoOggetto contesto — assegnane uno per drive
keybyte[16]La chiave AES di 16 byte per questo drive
tx_counteruint32Contatore TX iniziale (0 per prima messa in servizio, valore salvato al riavvio)
rx_counteruint32Contatore RX iniziale (0 per prima messa in servizio, valore salvato al riavvio)

4.2 Costruire un frame di richiesta di scrittura (FC6)

frame_len = NILAB_BuildWriteFrame(ctx, node_id, reg_address, value, frame_buf)

Costruisce un frame di scrittura FC6 crittografato completo, pronto per la trasmissione su RS-485.

ParametroTipoDescrizione
ctxhandleContesto inizializzato
node_iduint8Indirizzo slave Modbus
reg_addressuint16Indirizzo registro da scrivere
valueuint16Valore da scrivere
frame_bufbyte[]Buffer di uscita (minimo 23 byte)
valore di ritornointNumero di byte da trasmettere

4.3 Costruire un frame di richiesta di lettura (FC3)

frame_len = NILAB_BuildReadFrame(ctx, node_id, reg_address, qty, frame_buf)

Costruisce un frame di lettura FC3 crittografato completo per qty registri consecutivi.

4.4 Analizzare e decrittare un frame di risposta

status = NILAB_ParseResponse(ctx, raw_frame, frame_len, node_id, reg_values_out)

Verifica il tag di autenticazione, controlla il contatore e decritta la risposta del drive.

Valore di ritornoSignificato
NILAB_OK (0)Frame autenticato e decrittato con successo. reg_values_out valido.
NILAB_ERR_AUTH (1)Tag di autenticazione non corrisponde — frame falsificato, corrotto o chiave errata
NILAB_ERR_REPLAY (2)Contatore frame non crescente — possibile attacco replay
NILAB_ERR_SHORT (3)Frame troppo corto per essere una risposta crittografata valida
NILAB_ERR_TIMEOUT(4)Nessuna risposta ricevuta entro il timeout

4.5 Leggere i valori del contatore correnti (per la persistenza NVM)


tx_counter = NILAB_GetTxCounter(ctx)
rx_counter = NILAB_GetRxCounter(ctx)

Restituisce i valori del contatore correnti. Salva questi in memoria non volatile periodicamente e allo spegnimento (vedi Sezione 5).


5. Persistenza del contatore

Il meccanismo anti-replay richiede che il contatore TX master sia strettamente crescente attraverso i cicli di alimentazione. Sia tx_counter che rx_counter devono essere salvati in memoria non volatile e ripristinati all'avvio.

Strategia consigliata: ad ogni avvio PLC, inizializza il contesto con l'ultimo valore del contatore salvato più un margine di sicurezza (es. +1000). Questo garantisce che anche se la scrittura NVM è stata ritardata allo spegnimento, il contatore ripristinato è comunque più alto di qualsiasi contatore che il drive ha accettato nella sessione precedente.

Edit

5.1 CODESYS (variabili RETAIN)

VAR \RETAIN
  nTxCounterNVM : UDINT := 0;
  nRxCounterNVM : UDINT := 0;
END_VAR

(* All'avvio, una volta: *)
NILAB_Init(ctx, key, nTxCounterNVM + 1000, nRxCounterNVM);

(* Dopo ogni transazione riuscita: *)
nTxCounterNVM := NILAB_GetTxCounter(ctx);
nRxCounterNVM := NILAB_GetRxCounter(ctx);

Le variabili RETAIN CODESYS vengono salvate automaticamente su flash al ciclo di alimentazione — non è necessaria alcuna scrittura NVM aggiuntiva.

5.2 C / bare-metal

/* All'avvio: */
uint32_t tx_saved, rx_saved;
NVM_Read(&tx_saved, &rx_saved);   /* la tua funzione di lettura NVM */
NILAB_Init(&ctx, key, tx_saved + 1000, rx_saved);

/* Dopo ogni transazione riuscita: */
NVM_Write(NILAB_GetTxCounter(&ctx), NILAB_GetRxCounter(&ctx));

5.3 Prima messa in servizio

Alla prima messa in servizio (nessun dato NVM disponibile), passa 0 per entrambi i contatori. Il drive accetterà il primo frame dal contatore 0 e imposterà il suo riferimento interno di conseguenza.


6. Esempi di integrazione

Gli esempi seguenti mostrano la sequenza di chiamata tipica per i tre ambienti supportati. Essi presuppongono che la libreria sia stata importata nel progetto e che il contesto sia stato inizializzato nella sezione di avvio.

6.1 CODESYS V3.5 — Structured Text

Aggiungi la libreria NILAB al tuo progetto CODESYS tramite Tools → Library Manager → Add Library → NILAB_ModbusCrypto.

(*
 ---------------------------------------------------------------
 Avvio / inizializzazione (chiama una volta da PLC_PRG, primo scan)
 --------------------------------------------------------------- *)
\VAR
  ctx   : NILAB_Ctx;          (* Contesto crypto -- uno per drive *)
  key          : ARRAY[0..15] OF BYTE := [
                    16#1D, 16#23, 16#58, 16#6E, 16#43, 16#A2, 16#18, 16#62,
                    16#0E, 16#C5, 16#C7, 16#48, 16#62, 16#74, 16#CA, 16#D0 ];
  aFrame       : ARRAY[0..31] OF BYTE;
  aResponse    : ARRAY[0..31] OF BYTE;
  nFrameLen    : UDINT;
  nStatus      : INT;
  nRegValue    : WORD;
  bInitDone    : BOOL := FALSE;
END_VAR

IF NOT bInitDone \THEN
  NILAB_Init(ctx := ctx,
              key := key,
              tx_counter := nTxCounterNVM + 1000,
              rx_counter := nRxCounterNVM);
  bInitDone := TRUE;
END_IF

(*
 ---------------------------------------------------------------
 Scrivere registro 0x0010 = 0x1234 sul node \1
 --------------------------------------------------------------- *)
nFrameLen := NILAB_BuildWriteFrame(
              ctx         := ctx,
              node_id     := 1,
              reg_address := 16#0010,
              value       := 16#1234,
              frame_buf   := aFrame);

(* Inviare aFrame (nFrameLen byte) tramite il tuo blocco seriale/RS-485 *)
ComSend(port := COM1, data := aFrame, length := nFrameLen);

(* Attendere la risposta, poi: *)
ComReceive(port := COM1, data := aResponse, length => nRespLen);

nStatus := NILAB_ParseResponse(
             ctx       := ctx,
             raw_frame := aResponse,
             frame_len := nRespLen,
             node_id   := 1,
             reg_values_out := nRegValue);

IF nStatus = NILAB_OK \THEN
  (* scrittura confermata, nRegValue contiene il valore restituito *)
  nTxCounterNVM := NILAB_GetTxCounter(ctx);
  nRxCounterNVM := NILAB_GetRxCounter(ctx);
\ELSE
  (* gestire l'errore: nStatus = NILAB_ERR_AUTH, NILAB_ERR_REPLAY, ecc. *)
END_IF

(*
 ---------------------------------------------------------------
 Leggere registro 0x0020 sul node \1
 --------------------------------------------------------------- *)
nFrameLen := NILAB_BuildReadFrame(
              ctx         := ctx,
              node_id     := 1,
              reg_address := 16#0020,
              qty         := 1,
              frame_buf   := aFrame);

ComSend(port := COM1, data := aFrame, length := nFrameLen);
ComReceive(port := COM1, data := aResponse, length => nRespLen);

nStatus := NILAB_ParseResponse(
             ctx            := ctx,
             raw_frame      := aResponse,
             frame_len      := nRespLen,
             node_id        := 1,
             reg_values_out := nRegValue);

IF nStatus = NILAB_OK \THEN
  wMotorStatus := nRegValue;   (* usare il valore del registro *)
\END_IF

Sostituisci ComSend / ComReceive con i blocchi di funzione seriale effettivi disponibili nel tuo runtime CODESYS (es. SL_SER_SND / SL_SER_RCV su Wago, RS su IEC 61131-3 generico, blocchi master ModbusSerial se bypassi il livello del codice funzione). La libreria NILAB opera a livello di byte grezzi ed è indipendente dal blocco di trasporto seriale utilizzato.

6.2 C / C++ (bare-metal, RTOS, Linux)

Aggiungi nilab_modbus_crypto. h al tuo percorso di include e collega contro libnilab_modbus_crypto. a (ARM) o nilab_modbus_crypto. lib (x86 Windows).

#include "nilab_modbus_crypto.h"

/*
 --- Inizializzazione (chiama una volta all'avvio) --- */
static NILAB_Ctx g_ctx;

static const uint8_t g_key[16] = {
  0x1D, 0x23, 0x58, 0x6E, 0x43, 0xA2, 0x18, 0x62,
  0x0E, 0xC5, 0xC7, 0x48, 0x62, 0x74, 0xCA, \0xD0
};

void motor_comm_init(void)
{
  uint32_t tx_saved, rx_saved;
  NVM_Read(&tx_saved, &rx_saved);   /* la tua lettura NVM */
  NILAB_Init(&g_ctx, g_key, tx_saved + 1000, rx_saved);
}

/*
 --- Scrivere registro 0x0010 = 0x1234 sul node 1 --- */
int motor_write_register(uint16_t reg_addr, uint16_t value)
{
  uint8_t frame[32];
  uint8_t response[32];

  int flen = NILAB_BuildWriteFrame(&g_ctx, 1, reg_addr, value, frame);

  rs485_send(frame, flen);   /* il tuo invio RS-485 */
  int rlen = rs485_receive(response, sizeof(response), 200 /*ms*/);

  NILAB_Status st = NILAB_ParseResponse(&g_ctx, response, rlen, 1, NULL);

  if (st == NILAB_OK) {
      NVM_Write(NILAB_GetTxCounter(&g_ctx), NILAB_GetRxCounter(&g_ctx));
  }
  return (int)st;
}

/*
 --- Leggere registro 0x0020 sul node 1 --- */
int motor_read_register(uint16_t reg_addr, uint16_t *value_out)
{
  uint8_t frame[32];
  uint8_t response[32];

  int flen = NILAB_BuildReadFrame(&g_ctx, 1, reg_addr, 1, frame);

  rs485_send(frame, flen);
  int rlen = rs485_receive(response, sizeof(response), 200);

  NILAB_Status st = NILAB_ParseResponse(&g_ctx, response, rlen, 1, value_out);
  return (int)st;
}

6.3 Ladder Logic (generico)

Ladder Logic non ha supporto nativo per operazioni crittografiche a livello di byte. L'approccio consigliato per PLC basati su Ladder è:

Network 1: Blocco abilitazione sul fronte di salita di StartComm \contatto
--[P]--[StartComm]----[FB_NILAB.xEnable := TRUE]--

Network 2: Seleziona modalità di \scrittura
--[WriteCmd]----------[FB_NILAB.xWrite := TRUE]---
--[/WriteCmd]---------[FB_NILAB.xWrite := FALSE]--

Network 3: Passa indirizzo registro e \valore
--[MOVE]-- nTargetReg  --> FB_NILAB.\nRegAddress
--[MOVE]-- nSetpoint   --> FB_NILAB.nWriteValue

Network 4: Elabora il risultato su \Done
--[FB_NILAB.xDone]---[ProcessResultSubroutine]----

Network 5: Gestione \errori
--[FB_NILAB.xError]--[SET]--AlarmBit--------------

Per PLC che non supportano blocchi di funzione o subroutine Structured Text (sistemi a relè puro), la crittografia diretta non è fattibile a livello PLC. In questo caso, contatta NILAB per informazioni sul NILAB Crypto Gateway — un modulo esterno compatto che funge da ponte di crittografia trasparente tra la porta Modbus RTU standard del PLC e il bus dei drive.


7. Gestione degli errori

Tutte le funzioni API restituiscono un codice di stato. La seguente tabella descrive la risposta corretta a ogni condizione di errore in un'applicazione di macchina:

Codice di statoSignificatoAzione consigliata
NILAB_OKTransazione riuscitaOperazione normale, aggiorna i contatori NVM
NILAB_ERR_AUTHAutenticazione frame fallitaRegistra evento, riprova fino a 3 volte; se persistente, controlla la chiave
NILAB_ERR_REPLAYContatore non corrispondente o replay rilevatoRegistra evento, reimposta il contesto con NILAB_Init e contatori salvati
NILAB_ERR_SHORTFrame di risposta troppo corto o node ID erratoControlla cablaggio e terminazione RS-485
NILAB_ERR_TIMEOUTNessuna risposta ricevuta entro il timeoutControlla alimentazione drive, indirizzo e baud rate

In un'applicazione di asse rilevante per la sicurezza, qualsiasi errore persistente NILAB_ERR_AUTH o NILAB_ERR_REPLAY dovrebbe attivare un arresto immediato dell'asse e un allarme operatore. Questi errori non dovrebbero verificarsi in operazione normale e possono indicare manomissione o guasto hardware.


8. Risoluzione dei problemi

SintomoCausa probabileSoluzione
Il drive non risponde a nessun frameCrittografia abilitata, PLC invia in chiaroUsa la libreria NILAB. Tutti i frame in chiaro sono rifiutati by design.
Il drive risponde solo al primo frame dopo l'accensioneContatore non corrispondente dopo riavvio PLCRipristina i contatori salvati all'avvio (Sezione 5)
Errori NILAB_ERR_AUTH persistentiChiave errata per questo driveVerifica la chiave contro il database chiavi NILAB usando il numero di serie del drive
Errori NILAB_ERR_AUTH intermittentiRumore bus RS-485 che corrompe i frameControlla cavo, resistori di terminazione (120 Ω a entrambe le estremità), lunghezza cavo
NILAB_ERR_REPLAY dopo riavvio PLCContatore salvato più basso di quanto il drive si aspettaAumenta il margine di sicurezza NVM da +1000 a +10000 e ricommissiona
La comunicazione funziona ma il drive ignora i comandi di movimentoDrive in stato di errore/protezioneUsa NILAB Starter per controllare il registro guasti del drive prima del controllo PLC

9. Riferimento


Contatto e supporto

Per accesso alla libreria, provisioning delle chiavi o supporto tecnico di integrazione:

Voce
Web: www.nilab.at
Portale di supporto tecnico: www.ni-lab.online

Per segnalare una vulnerabilità di sicurezza nei prodotti NILAB: Segnala una vulnerabilità