Mục lục:

Giao tiếp mã hóa không dây Arduino: 5 bước
Giao tiếp mã hóa không dây Arduino: 5 bước

Video: Giao tiếp mã hóa không dây Arduino: 5 bước

Video: Giao tiếp mã hóa không dây Arduino: 5 bước
Video: Bài 5 Hướng dẫn sử dụng giao tiếp module bluetooth và Arduino 2024, Tháng mười một
Anonim
Giao tiếp mã hóa không dây Arduino
Giao tiếp mã hóa không dây Arduino

Chào mọi người, Trong bài viết thứ hai này, tôi sẽ giải thích cho bạn cách sử dụng chip Atecc608a để đảm bảo giao tiếp không dây của bạn. Đối với điều này, tôi sẽ sử dụng NRF24L01 + cho phần Không dây và Arduino UNO.

Vi chip ATECC608A được thiết kế bởi MicroChip và có nhiều công cụ bảo mật. Ví dụ, chip này có thể lưu trữ các Khóa ECC, Khóa AES (cho AES 128) và SHA2 Hash.

Bài viết: NRF24L01 + Arduino UNO + ATECC608A

Trong quá trình giao tiếp giữa hai Đối tượng IoT, có thể tồn tại nhiều cuộc tấn công: Người đàn ông nhẹ nhàng, Bản sao thông tin và hơn thế nữa.. Vì vậy, ý tưởng của tôi rất đơn giản:

  1. Sử dụng dữ liệu được mã hóa giữa hai hoặc nhiều đối tượng IoT.
  2. Nguồn cung cấp chi phí thấp
  3. Có thể hoạt động với Arduino UNO

Trong trường hợp của tôi, tôi sử dụng

  • Atecc608a để lưu trữ Khóa AES của tôi và để mã hóa / giải mã dữ liệu của tôi.
  • Arduino Uno làm Vi điều khiển
  • NRF24L01 để gửi dữ liệu của tôi

Bạn cần làm theo các bước sau cho dự án này:

  1. Thiết lập chip ATECC608A
  2. Làm mạch (Master Node và Slave Node)
  3. Phần mã
  4. Đi xa hơn !

Đối với các bước đầu tiên "Thiết lập chip ATECC608A", tôi đã viết một bài báo khác giải thích từng bước theo thứ tự. Liên kết ở đây:

Bây giờ bắt đầu!

Quân nhu

Đối với dự án này, bạn cần:

  • 2 Arduino UNO hoặc Arduino NANO hoặc Arduino Mega
  • Một số dây
  • 2 Atecc608a (mỗi chiếc có giá dưới 0,60 đô la)
  • 2 NRF24L01 +
  • 2 tụ điện (10 μF)
  • Bảng bánh mì

Liên kết đến bài viết của tôi giải thích cách thiết lập chip ATECC608A -> Cách thiết lập Atecc608a

Bước 1: 1. Thiết lập Atecc608a

1. Thiết lập Atecc608a
1. Thiết lập Atecc608a
1. Thiết lập Atecc608a
1. Thiết lập Atecc608a

Tôi sẽ không trình bày chi tiết từng bước cần làm để thiết lập ATECC608A vì tôi đã viết một bài báo đầy đủ giải thích mọi bước để thực hiện. Để thiết lập nó, bạn cần làm theo "Bước 4" của bài viết này có tên "2. Cấu hình chip (Atecc608a)"

Liên kết là: Cách thiết lập ATECC608A

Ngoài ra, bạn cần đặt cùng một cấu hình cho Atecc608a, phía chính và phía phụ, nếu không, bạn sẽ không thể giải mã dữ liệu của mình

Cảnh báo:

Để thiết lập chip này, bạn cần làm theo từng bước của bài viết trên theo thứ tự. Nếu thiếu một bước hoặc chip không khóa, bạn sẽ không thể thực hiện dự án này

Phần còn lại:

Bước để làm theo cho điều này:

  • Tạo mẫu cấu hình
  • Ghi mẫu này vào chip
  • Khóa vùng cấu hình
  • Viết Khóa AES của bạn (128 Bit) vào một chỗ trống
  • Khóa vùng dữ liệu

Bước 2: 2. Thiết kế mạch (Master và Slave)

2. Thiết kế của mạch (Master và Slave)
2. Thiết kế của mạch (Master và Slave)
2. Thiết kế của mạch (Master và Slave)
2. Thiết kế của mạch (Master và Slave)

Trong dự án này, bạn sẽ có Master Node và Slave Node.

Nút chính sẽ in rõ ràng dữ liệu được gửi bởi nút phụ. Nó sẽ yêu cầu dữ liệu từ nút nô lệ mỗi X lần.

Nút phụ sẽ lắng nghe "mạng" và khi nhận được "Dữ liệu yêu cầu", nó sẽ tạo ra nó, mã hóa nó và gửi đến nút chủ.

Đối với cả hai bên, mạch chủ và mạch phụ đều giống nhau:

  • Một Arduino Nano
  • Một ATECC608A
  • Một NRF24L01

Mình gắn mạch ở bước này (cf hình trên).

Đối với ATECC608A với Arduino UNO, đây là chân 8 soic. Tôi đã thêm "chế độ xem hàng đầu" ở trên:

  • ARDUINO 3.3V -> PIN 8 (Atecc608a)
  • ARDUINO GND -> PIN 4 (Atecc608a)
  • ARDUINO A4 (SDL) -> PIN 5 (Atecc608a)
  • ARDUINO A5 (SCL) -> PIN 6 (Atecc608a)

Đối với NRF24L01 vào Arduino:

  • ARDUINO 3.3V -> VCC (nrf24l01)
  • ARDUINO GND -> GND (nrf24l01)
  • ARDUINO 9 -> CE (nrf24l01)
  • ARDUINO 10 -> CSN (nrf24l01)
  • ARDUINO 11 -> MOSI (nrf24L01)
  • ARDUINO 12 -> MISO (nrf24l01)
  • ARDUINO 13 -> SCK (nrf24l01)
  • ARDUINO 3 -> IRQ (nrf24l01) -> chỉ dành cho nút Slave, không được sử dụng trong chế độ Chính

Tại sao sử dụng chân IRQ của NRF24L01

Chân IRQ rất hữu ích, chân này cho phép nói (THẤP) khi một gói được NRF24L01 nhận, vì vậy chúng ta có thể gắn một Interrupt vào chân này để đánh thức nút phụ.

Bước 3: 3. Mã (Slave và Master)

3. Mã (Slave và Master)
3. Mã (Slave và Master)

Nút nô lệ

Tôi sử dụng tiết kiệm năng lượng cho Node nô lệ vì nó không cần phải lắng nghe mọi lúc.

Cách thức hoạt động: nút nô lệ lắng nghe và đợi để nhận một "gói Wake UP". Gói tin này được gửi bởi nút Master để hỏi dữ liệu từ máy chủ.

Trong trường hợp của tôi, tôi sử dụng một mảng gồm hai int:

// Gói Wake UP

const int aw_packet [2] = {20, 02};

Nếu nút của tôi nhận được một gói,

  1. nó thức dậy, hãy đọc gói tin này, nếu gói đó là "Wake UP",
  2. nó tạo ra dữ liệu,
  3. mã hóa dữ liệu,
  4. gửi dữ liệu đến cái chính, đợi một gói ACK,
  5. ngủ.

Đối với Mã hóa AES, tôi sử dụng một khóa ở vị trí số 9.

Đây là mã của tôi cho nút Slave

#include "Arduino.h" #include "avr / sleep.h" #include "avr / wdt.h"

#include "SPI.h"

#include "nRF24L01.h" #include "RF24.h"

#include "Wire.h"

// Thư viện ATECC608A

#include "ATECCX08A_Arduino / cryptoauthlib.h" #include "AES BASIC / aes_basic.h"

#define ID_NODE 255

#define AES_KEY (uint8_t) 9

ATCAIfaceCfg cfg;

Trạng thái ATCA_STATUS;

Đài RF24 (9, 10);

const uint64_t masteraddresse = 0x1111111111;

const uint64_t slaveaddresse = 0x1111111100;

/**

* / short Hàm được thực thi khi ngắt được thiết lập (IRQ LOW) * * * / voidakeUpIRQ () {while (radio.available ()) {int data [32]; radio.read (& data, 32); if (data [0] == 20 && data [1] == 02) {float temp = 17,6; float hum = 16,4;

dữ liệu uint8_t [16];

uint8_t cypherdata [16];

// Xây dựng một chuỗi để đặt tất cả Giá trị của tôi

// Mỗi giá trị được phân tách bằng dấu "|" và "$" có nghĩa là cuối dữ liệu // CẢNH BÁO: Độ dài phải nhỏ hơn 11 String tmp_str_data = String (ID_NODE) + "|" + Chuỗi (tạm thời, 1) + "|" + Chuỗi (hum, 1) + "$"; // kích thước của 11 Serial.println ("tmp_str_data:" + tmp_str_data);

tmp_str_data.getBytes (dữ liệu, sizeof (dữ liệu));

// Mã hóa dữ liệu

ATCA_STATUS status = aes_basic_encrypt (& cfg, data, sizeof (data), cypherdata, AES_KEY); if (status == ATCA_SUCCESS) {long rand = random ((long) 10000, (long) 99999);

// tạo một UUID dựa trên ba số đầu tiên = nút ID

String uuid = String (ID_NODE) + String (rand); // Kích thước của 8

uint8_t tmp_uuid [8];

uint8_t data_to_send [32];

uuid.getBytes (tmp_uuid, sizeof (tmp_uuid) + 1);

memcpy (data_to_send, tmp_uuid, sizeof (tmp_uuid));

memcpy (data_to_send + sizeof (tmp_uuid), cypherdata, sizeof (cypherdata)); // Ngừng nghe radio.stopListening ();

bool rslt;

// Gửi dữ liệu rslt = radio.write (& data_to_send, sizeof (data_to_send)); // Bắt đầu nghe radio.startListening (); if (rslt) {// Chế độ kết thúc và nghỉ Serial.println (F ("Xong")); }}}}}

void setup ()

{Serial.begin (9600);

// Nhập hằng số cho thư viện

cfg.iface_type = ATCA_I2C_IFACE; // Kiểu giao tiếp -> Chế độ I2C cfg.devtype = ATECC608A; // Loại chip cfg.atcai2c.slave_address = 0XC0; // Địa chỉ I2C (giá trị mặc định) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Độ trễ đánh thức (1500 ms) cfg.rx_retries = 20;

radio.begin ();

radio.setDataRate (RF24_250KBPS); radio.maskIRQ (1, 1, 0); radio.enableAckPayload (); radio.setRetries (5, 5);

radio.openWritingPipe (masteraddresse);

radio.openReadingPipe (1, slaveaddresse); // Gắn ngắt vào chân 3 // Sửa đổi 1 bởi O nếu bạn muốn ngắt vào chân 2 // FALLING MODE = Pin tại LOW attachmentInterrupt (1, awUpIRQ, FALLING); }

void loop ()

{ // Không cần }

Nút chính

Node chính thức dậy sau mỗi 8 giây để yêu cầu dữ liệu từ Node nô lệ

Cách thức hoạt động: Nút chính gửi một gói "WakeUP" đến nô lệ và sau khi đợi một câu trả lời của nô lệ với dữ liệu.

Trong trường hợp của tôi, tôi sử dụng một mảng gồm hai int:

// Gói Wake UP

const int aw_packet [2] = {20, 02};

Nếu nút phụ gửi gói ACK sau khi nút chính gửi gói WakeUp:

  1. Thiết lập chính ở chế độ Nghe và chờ liên lạc
  2. Nếu giao tiếp
  3. Trích xuất 8 byte đầu tiên, lấy ba byte đầu tiên trong số 8 byte, nếu đây là nút ID
  4. Trích xuất 16 byte của cypher
  5. Giải mã dữ liệu
  6. In dữ liệu trong Serial
  7. Chế độ ngủ

Đối với Mã hóa AES, tôi sử dụng một khóa ở vị trí số 9.

Đây là mã của tôi cho nút Chính

#include "Arduino.h"

#include "avr / sleep.h" #include "avr / wdt.h" #include "SPI.h" #include "nRF24L01.h" #include "RF24.h" #include "Wire.h" // Thư viện ATECC608A #include "ATECCX08A_Arduino / cryptoauthlib.h" #include "AES BASIC / aes_basic.h" #define ID_NODE 255 #define AES_KEY (uint8_t) 9 ATCAIfaceCfg cfg; Trạng thái ATCA_STATUS; Đài RF24 (9, 10); const uint64_t masteraddresse = 0x1111111111; const uint64_t slaveaddresse = 0x1111111100; // Đánh thức gói tin const int aw_packet [2] = {20, 02}; // cơ quan giám sát ngắt ISR (WDT_vect) {wdt_disable (); // vô hiệu hóa cơ quan giám sát} void sleepmode () {// vô hiệu hóa ADC ADCSRA = 0; // xóa các cờ "đặt lại" khác nhau MCUSR = 0; // cho phép thay đổi, vô hiệu hóa thiết lập lại WDTCSR = bit (WDCE) | bit (WDE); // thiết lập chế độ ngắt và một khoảng WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // thiết lập WDIE, và độ trễ 8 giây wdt_reset (); // thiết lập lại watchdog set_sleep_mode (SLEEP_MODE_PWR_DOWN); noInterrupts (); // dãy định thời theo sau sleep_enable (); // tắt bật màu nâu trong phần mềm MCUCR = bit (BODS) | bit (BODSE); MCUCR = bit (BODS); ngắt (); // đảm bảo lệnh tiếp theo được thực thi sleep_cpu (); // hủy bỏ chế độ ngủ để đề phòng sleep_disable (); } void setup () {Serial.begin (9600); // Nhập hằng số cho thư viện cfg.iface_type = ATCA_I2C_IFACE; // Kiểu giao tiếp -> Chế độ I2C cfg.devtype = ATECC608A; // Loại chip cfg.atcai2c.slave_address = 0XC0; // Địa chỉ I2C (giá trị mặc định) cfg.atcai2c.bus = 1; cfg.atcai2c.baud = 100000; cfg.wake_delay = 1500; // Độ trễ đánh thức (1500 ms) cfg.rx_retries = 20; radio.begin (); radio.setDataRate (RF24_250KBPS); radio.maskIRQ (1, 1, 0); radio.enableAckPayload (); radio.setRetries (5, 5); radio.openWritingPipe (slaveaddresse); radio.openReadingPipe (1, masteraddresse); } void loop () {bool rslt; // Gửi dữ liệu rslt = radio.write (& aw_packet, sizeof (aw_packet)); if (rslt) {// Bắt đầu nghe radio.startListening (); while (radio.available ()) {uint8_t answer [32]; radio.read (& answer, sizeof (answer)); uint8_t node_id [3]; uint8_t cypher [16]; memcpy (node_id, answer, 3); memcpy (cypher, answer + 3, 16); if ((int) node_id == ID_NODE) {uint8_t output [16]; ATCA_STATUS status = aes_basic_decrypt (& cfg, cypher, 16, output, AES_KEY); if (status == ATCA_SUCCESS) {Serial.println ("Dữ liệu được giải mã:"); for (size_t i = 0; i <16; i ++) {Serial.print ((char) output ); }}}}} else {Serial.println ("Không nhận được cho Gói Wakup"); } // Chế độ ngủ 8 giây sleepmode (); }

Nếu bạn có câu hỏi, tôi ở đây để trả lời nó

Bước 4: 4. Đi xa hơn

Ví dụ này đơn giản để bạn có thể cải thiện dự án này

Cải tiến:

  • AES 128 là cơ bản và bạn có thể sử dụng một thuật toán khác của AES là AES CBC để an toàn hơn.
  • Thay đổi mô-đun không dây (NRF24L01 bị giới hạn bởi trọng tải 23 Byte)

Nếu bạn thấy cần cải thiện, hãy giải thích điều đó trên khu vực thảo luận

Bước 5: Kết luận

Tôi hy vọng bài viết này sẽ hữu ích cho bạn. Xin lỗi nếu tôi đã nhầm lẫn trong văn bản của mình nhưng tiếng Anh không phải là ngôn ngữ chính của tôi và tôi nói tốt hơn tôi viết.

Cảm ơn vì đã đọc tất cả mọi thứ.

Hãy tận hưởng nó.

Đề xuất: