×

らずらいと姫の挑戦日記 AES暗号化通信

2018-09-25

こんにちは。らずらいと姫です。
今回はRubyとC言語でAESの暗号化通信に挑戦してみたいと思います。

無線で通信をするということは、音声で会話しているのと同じように電波が届く範囲内であれば誰でもデータを受信することができてしまうそうです。920MHz無線であれば半径200~300mくらいしか届きませんし、鉄筋コンクリートの壁などは電波が通り抜けしづらいのですが、それでも他の人にデータを見られたくない、聞かれたくないという時があるかもしれません。

そのようなときに使用するのが通信データの暗号化です。

Lazuriteの暗号化通信では、送信機と受信機で同じ固定鍵を設定しておくことで暗号化を行い、そのデータがないとデータを受信しても中身を理解することができない状態にするできます。Lazuriteでは、AES128bitを用いて暗号化をしているそうです。

では早速使用してみましょう。

Lazurite SubGHz/920J側(送信機)にAES128bitの鍵情報を設定する。

Lazurite IDEの中のBINというファイルにAES128bitの鍵情報を生成するプログラムがあります。「aes_keygen.bat」というファイル名で次の一行を記載してください。
1の部分は送信機・受信機で鍵を生成するためのシーズになりますので、適当な数字に変更してください。1 〜 0xFFFFFFFFまで設定可能です。

c:\LazuriteIDE\bin\aes_keygen.ext 1 > aes_key.txt

作成したaes_key.txtの内容を見ると、このようになっています。

Seeds for Lazurite Pi Gateway::
07a45e454318b6d4a9d5449f3b342bda
Seeds for Lazurite SubGHz::
static const unsigned char key[] = {0x07,0xa4,0x5e,0x45,0x43,0x18,0xb6,0xd4,0xa9,0xd5,0x44,0x9f,0x3b,0x34,0x2b,0xda};

今回は、この「07a45e454318b6d4a9d5449f3b342bda」を暗号化の鍵として使用していきます。

Lazurite SubGHz/920J側に暗号化の鍵情報を設定する

Lazurite SubGHz/920J側は、鍵情報をunsigned char型の配列にしてあるこの情報を使用します。

static const unsigned char key[] = {0x07,0xa4,0x5e,0x45,0x43,0x18,0xb6,0xd4,0xa9,0xd5,0x44,0x9f,0x3b,0x34,0x2b,0xda};

この鍵情報をサンプルプログラム Welcome_SubGHz.cに追加してみます。
追加したサンプルコードは以下のとおりです。37行目、43行目が追加した行です。

#include "Welcome_SubGHz_ide.h" // Additional Header

/* FILE NAME: Welcome_SubGHz.c
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Lapis Semiconductor Co.,Ltd.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#define LED 26 // pin number of Blue LED
#define SUBGHZ_CH 36 // channel number (frequency)
#define SUBGHZ_PANID 0xabcd // panid
#define HOST_ADDRESS 0x8e6d // distination address

unsigned char send_data[] = {"Welcome to Lazurite Sub-GHz\r\n"};

//以下の一行を追加
static const unsigned char key[] = {0x07,0xa4,0x5e,0x45,0x43,0x18,0xb6,0xd4,0xa9,0xd5,0x44,0x9f,0x3b,0x34,0x2b,0xda};

void setup(void)
{

 SubGHz.init(); // initializing Sub-GHz
// 以下の一行を追加
 SubGHz.setKey(key);
 Serial.begin(115200);
 pinMode(LED,OUTPUT); // setting of LED
 digitalWrite(LED,HIGH); // setting of LED
}

void loop(void)
{
 SUBGHZ_MSG msg;
 // Initializing
 SubGHz.begin(SUBGHZ_CH, SUBGHZ_PANID, SUBGHZ_100KBPS, SUBGHZ_PWR_20MW); // start Sub-GHz

 // preparing data
 digitalWrite(LED,LOW); // LED ON
 msg=SubGHz.send(SUBGHZ_PANID, HOST_ADDRESS, &send_data, sizeof(send_data),NULL);// send data
 digitalWrite(LED,HIGH); // LED off
 SubGHz.msgOut(msg);

 // close
 SubGHz.close(); // Sub-GHz module sets into power down mode.

 sleep(1000); // sleep

 return;
}

Raspberry Pi側で鍵情報を生成する

Raspberry Pi側は、次のところに鍵情報を生成するプログラムのソースコードが保存されています。プログラムをビルドして実行可能なファイルを生成する必要があります。そして、同じく「1」を鍵情報のシーズとしてAESの鍵情報を生成します。

cd ~/driver/LazDriver/aes_keygen/
make
./aes_keygen 1 > aes_key.txt

 

 

~/driver/LazDriver/aes_keygen/aes_key.txtに、同じ鍵情報が記録されているはずです。

Rubyで受信する

rubyの受信用プログラムを起動します。

cd ~/driver/LazGem/sample
./sample_rx.rb 36

そうすると、次のようにpayloadの部分がよくわからない情報になっているのが確認できます。

{“header”=>43049, “dst_addr_type”=>2, “frame_ver”=>2, “src_addr_type”=>2, “ielist”=>0, “seq_comp”=>0, “panid_comp”=>0, “ack_req”=>1, “pending”=>0, “sec_enb”=>1, “frame_type”=>1, “addr_type”=>6, “dst_panid”=>43981, “src_panid”=>nil, “dst_addr”=>36461, “src_addr”=>17706, “seq_num”=>60, “payload”=>”\xF0\xE7\x95\x9FT\x9A\xA8\xBA\x90Z\x7F\xFE\x94\xCB\b\x8C\xEF)nD\x8B7\x19\x809\xC0,*\x01l\xCDg”, “sec”=>1537843237, “nsec”=>349094568, “rssi”=>224}

rubyのサンプルソースコードに、AESの鍵情報を設定します。~/driver/LazGem/sample_rx.rbの48行目付近にLaz.setKey(“xxxxxx”)の一行を追加します。

#! /usr/bin/ruby
# -*- coding: utf-8; mode: ruby -*-
# Function:
# Lazurite Sub-GHz/Lazurite Pi Gateway Sample program
# SerialMonitor.rb
require 'LazGem'

laz = LazGem::Device.new

# Halt process when CTRL+C is pushed.
finish_flag=0
Signal.trap(:INT){
 finish_flag=1
}

if ARGV.size == 0
 printf("please input argument of ch at least\n")
 printf("command format is shown below...\n")
 printf("./sample_rx.rb ch panid baud pwr\n")
 printf(" ch: 24-61\n")
 printf(" panid: 0-0xffff\n")
 printf(" baud: 50 or 100\n")
 printf(" pwr: 1 or 20\n")
 exit 0
end

# open device deriver

dst_addr = 0xffff
ch = 36
panid = 0xabcd
baud = 100
pwr = 20

if ARGV.size > 0
 ch=Integer(ARGV[0])
end
if ARGV.size > 1
 panid = Integer(ARGV[1])
end
if ARGV.size > 2
 baud = Integer(ARGV[2])
end
if ARGV.size > 3
 pwr = Integer(ARGV[3])
end

laz.init()
laz.setKey("07a45e454318b6d4a9d5449f3b342bda")

print(sprintf("myAddress=0x%016x\n",laz.getMyAddr64()))
print(sprintf("myAddress=0x%04x\n",laz.getMyAddress()))

laz.begin(ch,panid,baud,pwr)
laz.rxEnable()

# printing header of receiving log
print(sprintf("time\t\t\t\t\t[ns]\trxPanid\trxAddr\ttxAddr\trssi\tpayload\n"))
print(sprintf("------------------------------------------------------------------------------------------\n"))

# main routine
while finish_flag == 0 do
 if laz.available() <= 0
 sleep 0.01
 next
 end
 rcv = laz.read()
 # printing data
 p rcv
end

# finishing process
laz.remove()

そして、もう一度 sample_rx.rbを起動してみると、次のようにpayloadの部分が正しく読めるデータになっているのが確認できます。

{“header”=>43049, “dst_addr_type”=>2, “frame_ver”=>2, “src_addr_type”=>2, “ielist”=>0, “seq_comp”=>0, “panid_comp”=>0, “ack_req”=>1, “pending”=>0, “sec_enb”=>1, “frame_type”=>1, “addr_type”=>6, “dst_panid”=>43981, “src_panid”=>nil, “dst_addr”=>36461, “src_addr”=>17706, “seq_num”=>191, “payload”=>“Welcome to Lazurite Sub-GHz\r\n\x00”, “sec”=>1537846994, “nsec”=>13026693, “rssi”=>201}

 

C言語で受信する

続いてC言語で動作させてみます。

cd ~/driver/liblazurite/sample/
./sample_rx_raw 36

鍵情報を設定しない状態ではこのように文字化けしてしまいました。

set_nokey

sample_rx_raw.cppの58行目と69行目付近に、鍵情報を設定する行の追加を行います。

/*!
 @file test_rx.cpp
 @brief about test_raw <br>
 sample code to read raw data that is received.

 @subsection how to use <br>

 paramete can be ommited.
 
 (ex)
 @code
 test_raw 36 0xabcd 100 20
 test_raw 36 0xabcd
 @endcode

 when push Ctrl+C, process is quited.
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "../lib/liblazurite.h" 

using namespace lazurite;
bool bStop;

/*!
 signal handler <br>
 this process is executed, when Ctrl+C is pushed.
 */
void sigHandle(int sigName)
{
 bStop = true;
 printf("sigHandle = %d\n",sigName);
 return;
}
/*!
 set signal handler for Ctrl+C
 */

int setSignal(int sigName)
{
 if(signal(sigName,sigHandle)==SIG_ERR) return -1;
 return 0;
}
int main(int argc, char **argv)
{
 int result;
 char* en;
 uint8_t ch=36;
 uint8_t rate=100;
 uint8_t pwr=20;
 uint16_t panid=0xabcd;
 uint8_t myaddr_be[8];
 static char key[] = "07a45e454318b6d4a9d5449f3b342bda";

 // set Signal Trap
 setSignal(SIGINT);

 timespec rxTime;

 if((result=lazurite_init())!=0) {
 printf("liblzgw_open fail = %d\n",result);
 return EXIT_FAILURE;
 }
 lazurite_setKey(key);

 bStop = false;
 if(argc>1) {
 ch = strtol(argv[1],&en,0);
 }
 if(argc>2) {
 panid = strtol(argv[2],&en,0);
 }
 if(argc>3) {
 rate = strtol(argv[3],&en,0);
 }
 if(argc>4) {
 pwr = strtol(argv[4],&en,0);
 }

 printf("short address:: %04x\n",lazurite_getMyAddress());
 result = lazurite_getMyAddr64(myaddr_be);
 printf("mac address:: %02x%02x%02x%02x %02x%02x%02x%02x\n",
 myaddr_be[0],
 myaddr_be[1],
 myaddr_be[2],
 myaddr_be[3],
 myaddr_be[4],
 myaddr_be[5],
 myaddr_be[6],
 myaddr_be[7]
 );

 result = lazurite_begin(ch,panid,rate,pwr);
 if(result < 0) {
 printf("lazurite_begin fail = %d\n",result);
 return EXIT_FAILURE;
 }
 result = lazurite_rxEnable();
 if(result < 0) {
 printf("lazurite_rxEnable fail = %d\n",result);
 return EXIT_FAILURE;
 }

 while(bStop == false)
 {
 uint16_t size;
 uint8_t rssi;
 SUBGHZ_MAC mac;
 char raw[256];
 memset(raw,0,sizeof(raw));
 result = lazurite_read(raw,&size);
 if(result > 0 ) {
 result = lazurite_decMac(&mac,raw,size);
 printf("%02x\t%04x\t%02x%02x%02x%02x%02x%02x%02x%02x\t%04x\t%02x%02x%02x%02x%02x%02x%02x%02x\t",
 mac.seq_num,
 mac.dst_panid,
 mac.dst_addr[7],
 mac.dst_addr[6],
 mac.dst_addr[5],
 mac.dst_addr[4],
 mac.dst_addr[3],
 mac.dst_addr[2],
 mac.dst_addr[1],
 mac.dst_addr[0],
 mac.dst_panid,
 mac.src_addr[7],
 mac.src_addr[6],
 mac.src_addr[5],
 mac.src_addr[4],
 mac.src_addr[3],
 mac.src_addr[2],
 mac.src_addr[1],
 mac.src_addr[0]
 );
 printf("%s\n", raw+mac.payload_offset);
 }
 usleep(100000);
 }

 if((result = lazurite_close()) !=0) {
 printf("fail to stop RF %d",result);
 }
 usleep(100000);
 if((result = lazurite_remove()) !=0) {
 printf("remove driver from kernel %d",result);
 }
 return 0;
}

 

編集したら、コンソール画面でmakeとうち、プログラムをビルドしてください。

make

新しいプログラムを実行したら、データの部分が正しく表示されるようになりました。

set_aeskey

以上、今回はAES暗号化をRuby, Cで動かすサンプルプログラムの紹介を行いました。ぜひ、お試しください。