suculent / thinx-aes-lib

AES wrapper for ESP8266/ESP32/Arduino/nRF5x
Other
113 stars 39 forks source link

No randomness in IV #55

Closed koshkamau closed 1 year ago

koshkamau commented 2 years ago

I'm trying to use this library in my Arduino sketch to encrypt data from a sensor (ESP8266) to server. I'm just at the beginning of this path so I haven't tested actual encryption yet, but from my debug messages seems that IV is not initialized by random data. I always get 0x2F values.

byte aes_iv[N_BLOCK] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF };

void somefunc(){
    aes_init(); 
    for(int i=0;i<16;i++) DBG_COMPORT.printf("%02x ", aes_iv[i]);
}

void aes_init() {
  aesLib.gen_iv(aes_iv);
  aesLib.set_paddingmode((paddingMode)0);
}

On the DBG_COMPORT I get:

2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f`

suculent commented 2 years ago

IV is not random in examples to ease up debugging.

Once you have random IV, you need to make sure you have it ready on decryption, which often means transmitting it with encrypted block.

M.

On 5. 8. 2021, at 4:57, koshkamau @.***> wrote:

 I'm trying to use this library in my Arduino sketch to encrypt data from a sensor (ESP8266) to server. I'm just at the beginning of this path so I haven't tested actual encryption yet, but from my debug messages seems that IV is not initialized by random data. I always get 0x2F values.

byte aes_iv[N_BLOCK] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF };

void somefunc(){ aes_init(); for(int i=0;i<16;i++) DBG_COMPORT.printf("%02x ", aes_iv[i]); }

void aes_init() { aesLib.gen_iv(aes_iv); aesLib.set_paddingmode((paddingMode)0); }

On the DBG_COMPORT I get:

2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f 2f`

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.

koshkamau commented 2 years ago

Thank you, I already understand that (it took me a couple of days though :) ). I do not use examples AS IS. I call aes_init() and right after that I print IV contents to comport as I showed above. It always has 2f in each byte. I also tried to write #define ESP8266 1 without success. It looks like srand/rand doesn't work for me (or I made some stupid mistake among my three lines of code) - I will investigate further today.

I use Arduino IDE with AESLib library 2.2.1 installed using library manager.

suculent commented 2 years ago

Try aesLib.gen_iv(aes_iv);

On 5. 8. 2021, at 12:13, koshkamau @.***> wrote:

 Thank you, I already understand that (it took me a couple of days though :) ). I do not use examples AS IS. I call aes_init() and right after that I print IV contents to comport as I showed above. It always has 2f in each byte. I also tried to write #define ESP8266 1 without success. It looks like srand/rand doesn't work for me (or I made some stupid mistake among my three lines of code) - I will investigate further today.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

koshkamau commented 2 years ago

The problem is in function AES::getrandom

1) it seems strange to me - to call srand() before each rand(), but I'm no expert. 2) In case of ESP8266 before each rand() there is a call srand ((unsigned int)time(NULL)); which resets the value, generated by rand() to a certain value. It sets this value even if I add a few milliseconds delay between calls. I don't know why it happens I just did a test:

DBG_COMPORT.println();
srand ((unsigned int)time(NULL));
DBG_COMPORT.println(rand());
srand ((unsigned int)time(NULL));
DBG_COMPORT.println(rand());
srand ((unsigned int)time(NULL));
DBG_COMPORT.println(rand());
DBG_COMPORT.println(rand());
DBG_COMPORT.println(rand());
DBG_COMPORT.println(rand());

This test prints three identical values and then three different values. It seems that srand ((unsigned int)time(NULL)); is faulty and it is called before each rand so it actually prevents random number generator to work.

3) In other branch of AES::getrandom before each rand() there is a call srand (millis()); Though it works correctly, it uses milliseconds to initialize RNG. So if we are requesting some random numbers during one millisecond - we get identical numbers. So, delay of a few ms should be added between calls to AES::getrandom or srand() should be called only once somewhere to initialize RNG.

suculent commented 2 years ago

Well, this is a bit of problem, as ESP8266 does not provide true secure random number generator and the time after boot is usually same.

There's just RANDOM_REG32 at ((volatile int)0x3FF20E44) but I haven't tried that as the code would not be compatible with Arduino anymore – implemetation would have to be split.

I would personally use hardware TRNG on I2C/SPI bus to achieve true randomness, like https://www.microchip.com/en-us/product/ataes132a.

For FPGA people also https://www.dialog-semiconductor.com/products/greenpak/slg46620 as in https://www.dialog-semiconductor.com/greenpak-application-notes/an-1200-true-random-number-generator-hardware.

On 6. 8. 2021, at 2:18:55, koshkamau @.***> wrote:

The problem is in function AES::getrandom

it seems strange to me - to call srand() before each rand(), but I'm no expert. In case of ESP8266 before each rand() there is a call srand ((unsigned int)time(NULL)); which resets the value, generated by rand() to a certain value. It sets this value even if I add a few milliseconds delay between calls. I don't know why it happens I just did a test: DBG_COMPORT.println(); srand ((unsigned int)time(NULL)); DBG_COMPORT.println(rand()); srand ((unsigned int)time(NULL)); DBG_COMPORT.println(rand()); srand ((unsigned int)time(NULL)); DBG_COMPORT.println(rand()); DBG_COMPORT.println(rand()); DBG_COMPORT.println(rand()); DBG_COMPORT.println(rand()); This test prints three identical values and then three different values. It seems that srand ((unsigned int)time(NULL)); is faulty and it is called before each rand so it actually prevents random number generator to work.

In other branch of AES::getrandom before each rand() there is a call srand (millis()); Though it works correctly, it uses milliseconds to initialize RNG. So if we are requesting some random numbers during one millisecond - we get identical numbers. So, delay of a few ms should be added between calls to AES::getrandom or srand() should be called only once somewhere to initialize RNG. — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/suculent/thinx-aes-lib/issues/55#issuecomment-893910277, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABWFR644H4V7QLUQHZGXF3T3MS67ANCNFSM5BSQHDSA.

suculent commented 2 years ago

Any advance in this? I'm picking issues to look into...

koshkamau commented 2 years ago

Instead of fighting with this library I did an obfuscation of my messages. XOR + cyclic shift + change byte order. Operations are based on arrays of random bytes, generated on PC. Fast, small and secure enough for a water leakage sensor :)

suculent commented 2 years ago

The problem is apparently that void AESLib::gen_iv(uint8_t * iv) does call getrandom() always at the same time. Anyway, for a water leakage sensor, you should use stream cipher instead of block cipher. Something like ChaCha/Poly from https://github.com/kostko/arduino-crypto

Question is, whether it's worth it. You don't want anyone to MITM start your alarm, of course. But the data are maybe not essentialy secret at all.

Problem is adding arbitrary static delay into getrandom()... in case the delay is seeded from network communication (e.g. timestamp) it will be always really random, but once it is calculated right after boot, it will be always same since the time will be always about same from the boot time 0.

hansliss commented 1 year ago

The whole point of a PRNG is that it provides a new value every time you calculate it. You should seed it before using it the first time, but you should not seed it on every call, since that defeats the whole point of a PRNG. If it's called several times in a row within a millisecond and seeded with millis() every time, all of the values will be the same. I would suggest that you hand this problem over to the user, and tell them that the PRNG must be seeded, once, before using the library.

suculent commented 1 year ago

Solution by @hansliss has been incorporated into latest release. Thanks.