Go Down

Topic: new AES library (Read 86576 times) previous topic - next topic

casloureiro

Hello,

I have a program where I have several strings. To avoid the use of RAM, I'm using the PROGMEM to have array of strings, and also the F() to store strings on the flash (PGM).

I'm using a arduino mega2560, and I see if changes some strings to the flash, with F(), I start having problems with the encoding and decondig.

I have arrived to the point where I have a program with 83346 bytes (32% of program space). And all is working.

If I change the line:

Code: [Select]
_lcd->print("1) ");

to

_lcd->print(F("1) "));


The program size jumps to 83598 bytes, and the encode and decode doesn't work correctly.
I have made several changes on the code, but always I get a program above the 83346 I get problems on the AES library. All the rest is working.

I see that the library also uses PGM to store values.

My question, is there the possibility that the use of several strings stored on the PGM, could cause problem on the library?

I'm using AES CBC 128bits.

Thanks for any idea that can be shared.

-dev

Quote
Thanks for any idea that can be shared.
It is probably a near vs. far address problem.  Most pointers, like "const char *" or "const __FlashStringHelper *", are 16-bit addresses (i.e., "near" in the first 64K).

For function calls to "far" destinations, the linker is "supposed" to use a "trampoline" to get there, jumping to a "near" address first.  I get the impression that far calls are usually handled correctly.

For "far" data, I can't find anything other than managing it yourself with explicit declarations like uint_farptr_t and xxxx_PF variants, like memcpy_PF.

I don't think FLASH data (e.g., declared via the F macro) is guaranteed to be anywhere in particular.  The sketch code is preferentially loaded in the first 64K, but libraries may extend past that boundary.  I wonder if the code size pushes FLASH data past the 64K address boundary.  Then it is dereferenced incorrectly by code that expectes near pointers (e.g., Print methods).

To force the code to use far pointers for FLASH data, you have to do something like this:

Code: [Select]
const char someFlashData[] PROGMEM = "stringity string.";

void farPrint( const char *farFD )
{
  uint_farptr_t farAddr = pgm_get_far_address( farFD );
 
  do {
    char c = pgm_read_byte_far( farAddr++ );
    if (!c)
      break;
    Serial.write( c );
  }
}

void foo()
{
  farPrint( someFlashData );
}

Untested.   Functions/macros documented here.

If the AES library is using FLASH data, it would have to be modified to always use far pointers.  If it's just your sketch that is using FLASH data, you *should* be able to modify all the F macro uses to do something different.  Initial values may also fall into that category: they are loaded from FLASH into the RAM variable being initialized.

That's about all I can suggest.  Free advice is worth what you paid for it, my $0.02, YMMV, etc., etc.

You've been warned.  ;)
Really, I used to be /dev.  :(

spatula

I am trying to use this library to encrypt some data I'm sending to a Raspberry Pi using a transceiver module. In order to make a small test prototype I've modified the example code provided with this library so that it performs 256 2 block CBC encryption and then prints the cipher to the Serial monitor.
Code: [Select]

#include <AES.h>

AES aes ;

byte key[] =
{
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte plain[] =
{
  // 0xf3, 0x44, 0x81, 0xec, 0x3c, 0xc6, 0x27, 0xba, 0xcd, 0x5d, 0xc3, 0xfb, 0x08, 0xf2, 0x73, 0xe6
  0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte my_iv[] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
} ;

byte cipher [4*N_BLOCK] ;
byte check [4*N_BLOCK] ;

void loop ()
{}


void setup ()
{
  Serial.begin (57600) ;
  Serial.print ("testng mode") ;

  prekey_test () ;
 
//  otfly_test () ;
//  otfly_test256 () ;
}

void prekey (int bits, int blocks)
{
  byte iv [N_BLOCK] ;
 
  long t0 = micros () ;
  byte succ = aes.set_key (key, bits) ;
  long t1 = micros()-t0 ;
  Serial.print ("set_key ") ; Serial.print (bits) ; Serial.print (" ->") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;
  t0 = micros () ;
  if (blocks == 1)
    succ = aes.encrypt (plain, cipher) ;
  else
  {
    for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;
    succ = aes.cbc_encrypt (plain, cipher, blocks, iv) ;
  }
  t1 = micros () - t0 ;
  Serial.print ("encrypt ") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;
  Serial.println();
  Serial.println("-------------------");
  for(byte i = 0; i < sizeof(cipher); i++) {
    Serial.print(cipher[i], HEX);
  }
  Serial.println("");
  Serial.println("------------------------------");

}

void prekey_test ()
{
  prekey (256,2) ;

}


I am then taking the cipher text and copying it to Python on the Raspberry Pi to the decryption code which uses the pycryptodome library, which is where I don't understand what to do. I am unsure of the block length of this library (I've serially printed N_BLOCK and found it to be 16, but the cipher array is 64 bytes long...) and I continually get a padding error in Python. I realise this is more of a Python problem than anything else but I have tried everything I can think of.

Code: [Select]


from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from Crypto.Util.Padding import pad, unpad

BLOCK_SIZE = 64 # is that right?

def encrypt(plaintext, key, IV):
    cipher = AES.new(key, AES.MODE_CBC, IV)
    cipher_bytes = cipher.encrypt(pad(plaintext, BLOCK_SIZE))
    return(cipher_bytes)

def decrypt(ct, passkey, IV):
    cipher = AES.new(passkey, AES.MODE_CBC, IV)
    decrypted = cipher.decrypt(ct)
    return((unpad(decrypted, BLOCK_SIZE)))

passkey = b'80000000000000000000000000000000' #have I converted the passkey from the example code correctly?
IV = b'0000000000000001' # have I converted the IV from the example code correctly?
ct = b"F7B337A3C81C50169E4851F823E8C8B78EB31B013171CA23641F0D385DB38B00000000000000000000000000000000"
print(decrypt(ct, passkey, IV))

"""
>> ValueError: Data must be padded to 16 byte boundary in CBC mode

"""


Go Up