Recently I had a chance to play with i2c-stub. The goal was to send and receive encrypted data to/from I2C connected device. I didn’t want to play with real I2C device, so I needed to emulate it somehow, which is possible with i2c-stub on linux. Here below is description how it was done.

Requirements

The solution needs to be implemented in C and have following functionalities

  • Possibility to connect to I2C slave
  • Send encrypted data
  • Receive and decrypt data
  • Possibility to check connection status

The code

The code itself is here. To compilie with gcc simply download and make.

Initialization

In order to use the code (read/write data to I2C) I’m using i2c-stub linux module and i2c-tools package (ArchLinux). i2c-stub creates a fake I2C adapter(Controller/Master) and emulates i2C hardware (using array to store data). We also will need i2c-dev module as a frontend.

Following command will load the module, initialize slave device with an address 0x03, and read it’s initial state:

> modprobe i2c-dev
> modprobe i2c-stub chip_addr=0x03

> i2cdetect -l
i2c-1   i2c         i915 gmbus dpc                      I2C adapter
i2c-2   i2c         i915 gmbus dpd                      I2C adapter
...
i2c-8   smbus       SMBus stub driver                   SMBus adapter <-- this one
...

> i2cdump -y 8 0x03
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

We can see that module was loaded. i2cdetect as detected is as a character device /dev/i2c-8 and i2c-dump shows memory state of slave device with an ID 0x03.

Sending data

Test program has -s option that needs to be used in order to send data. As an argument, device ID needs to be provided.

> ./bin/main -s 8 && echo $?
0

On a success program return 0. We can now verify if data has been stored in the i2c device with i2cdump.

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 1f f8 47 8e 7f 24 1d 2b 47 ca 64 be ce 0a 3f bd    ??G??$?+G?d?????
10: 08 1c 05 87 b0 31 6c 85 46 94 6f c8 9e 49 dd b2    ?????1l?F?o??I??
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

Before sending program uses Poly1305-ChaCha20 to encrypt and authenticate data.

Receiving data

Test program has -r option to indicate that user want’s to receive data from I2C device. On exit program prints received data.

[root@cryptoden final]# ./bin/main -r 8
RECEIVED DATA:
HELLO WORLD!!!

As data is authenticated any change to data stored in the I2C will result in decryption error. In order to see this behaviour one can dump the I2C memory, change it, load to I2C and try to read again. Let’s see this:

> i2cdump -y 8 0x03 b > dump
> cat dump
[root@cryptoden ~]# cat dump
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 1f f8 47 8e 7f 24 1d 2b 47 ca 64 be ce 0a 3f bd    ??G??$?+G?d?????
10: 08 1c 05 87 b0 31 6c 85 46 94 6f c8 9e 49 dd b3    ?????1l?F?o??I??
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

## Here I modify 32-nd byte from b3 to b2 and load data to i2c-stub
> i2c-stub-from-dump 0x03 dump
256 byte values written to 8-0003

## Trying to read
> ./bin/main -r 8
[i2c_recv() src/i2c.c:165] Error occured when decrypting
[i2c_recv() src/i2c.c:172] ERROR: can't receive encrypted data
[test_receive() src/main.c:88] Error occured when receiving data

Testing

Program has a -t option which can be used to test program and see that connection stays persistent after connecting to the device.

> ./bin/main -t 8 && echo $?
0