1 // *********************************************************************
    2 //   Custom DPA Handler code example - User data en/decryption         *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-UserEncryption.c,v $
    7 // Version: $Revision: 1.10 $
    8 // Date:    $Date: 2017/08/09 12:24:47 $
    9 //
   10 // Revision history:
   11 //   2017/03/13  Release for DPA 3.00
   12 //
   13 // *********************************************************************
   14 
   15 // On-line DPA documentation http://www.iqrf.org/DpaTechGuide/
   16 
   17 /* This example shows the usage of the user data en/decryption using AES-128
   18 
   19 User peripheral PNUM=0x20 and 2 commands are implemented:
   20 * PCMD=0 returns first 16 bytes of peripheral RAM encrypted by User key
   21 * PCMD=1 writes 16 bytes of data encrypted by the User key to the peripheral RAM
   22 
   23 The initial content of the peripheral RAM after the device is restarted is 0,1,2,3,4,5,6,7,8,"AES-128". 
   24 
   25 You can use a public on-line AES tools to en/decrypt to play with the commands.
   26 
   27 [Example 1]
   28 * Restart module
   29 * Run PCMD=0. It returns the initial text from peripheral RAM encrypted by the User key (initial value is 00000000000000000000000000000000). Returned data is ce61d785c84e30883973340aea2e6dcf
   30 * Go to http://testprotect.com/appendix/AEScalc
   31 * Enter 00000000000000000000000000000000 to "AES key (in hex):"
   32 * Enter ce61d785c84e30883973340aea2e6dcf to "Input Data (in hex):"
   33 * Press "Decrypt it", the result is 0001020304050607084145532d313238, which corresponds to the expected 0,1,2,3,4,5,6,7,8,"AES-128"
   34 
   35 [Example 2]
   36 * Go to http://testprotect.com/appendix/AEScalc
   37 * Enter 00000000000000000000000000000000 to "AES key (in hex):"
   38 * Enter aaBBccDDeeFFaaBBccDDeeFFaaBBccDD to "Input Data (in hex):"
   39 * Press "Encrypt it", the result is e37967714d9be9e66bc03629427de452
   40 * Run PCMD=1 with data "e37967714d9be9e66bc03629427de452"
   41 * Read 16 bytes from address 0 of peripheral Ram. The result is expected aaBBccDDeeFFaaBBccDDeeFFaaBBccDD
   42 
   43 Note: another AES tool that works well is http://aes.online-domain-tools.com/
   44 
   45 */
   46 
   47 // The example will not work at demo DPA version because demo DPA does not support PCMD != 0
   48 
   49 // Default IQRF include (modify the path according to your setup)
   50 #include "IQRF.h"
   51 
   52 // Default DPA header (modify the path according to your setup)
   53 #include "DPA.h"
   54 // Default Custom DPA Handler header (modify the path according to your setup)
   55 #include "DPAcustomHandler.h"
   56 
   57 //############################################################################################
   58 
   59 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   60 //############################################################################################
   61 bit CustomDpaHandler()
   62 //############################################################################################
   63 {
   64   // Handler presence mark
   65   clrwdt();
   66 
   67   // Detect DPA event to handle
   68   switch ( GetDpaEvent() )
   69   {
   70     // -------------------------------------------------
   71     case DpaEvent_Interrupt:
   72       // Do an extra quick background interrupt work
   73       // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible.
   74       // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one.
   75       // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time.
   76       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   77       // ! Make sure race condition does not occur when accessing those variables at other places.
   78       // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt.
   79       // ! Do not call any OS functions except setINDFx().
   80       // ! Do not use any OS variables especially for writing access.
   81       // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage.
   82 
   83       return Carry;
   84 
   85       // -------------------------------------------------
   86     case DpaEvent_Init:
   87       // Do a one time initialization work before main loop starts
   88 
   89       // Initialize en/decrypted user data
   90       PeripheralRam[0x0] = 0;
   91       PeripheralRam[0x1] = 1;
   92       PeripheralRam[0x2] = 2;
   93       PeripheralRam[0x3] = 3;
   94       PeripheralRam[0x4] = 4;
   95       PeripheralRam[0x5] = 5;
   96       PeripheralRam[0x6] = 6;
   97       PeripheralRam[0x7] = 7;
   98       PeripheralRam[0x8] = 8;
   99       PeripheralRam[0x9] = 'A';
  100       PeripheralRam[0xA] = 'E';
  101       PeripheralRam[0xB] = 'S';
  102       PeripheralRam[0xC] = '-';
  103       PeripheralRam[0xD] = '1';
  104       PeripheralRam[0xE] = '2';
  105       PeripheralRam[0xF] = '8';
  106       break;
  107 
  108       // -------------------------------------------------
  109     case DpaEvent_DpaRequest:
  110       // Called to interpret DPA request for peripherals
  111       // -------------------------------------------------
  112       // Peripheral enumeration
  113       if ( IsDpaEnumPeripheralsRequest() )
  114       {
  115         // We implement 1 user peripheral
  116         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  117         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 );
  118         _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F;
  119         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x1234;
  120 
  121 DpaHandleReturnTRUE:
  122         return TRUE;
  123       }
  124       // -------------------------------------------------
  125       // Get information about peripheral
  126       else if ( IsDpaPeripheralInfoRequest() )
  127       {
  128         if ( _PNUM == PNUM_USER + 0 )
  129         {
  130           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA;
  131           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  132           goto DpaHandleReturnTRUE;
  133         }
  134 
  135         break;
  136       }
  137       // -------------------------------------------------
  138       else
  139       {
  140         // Handle peripheral command
  141         if ( _PNUM == PNUM_USER + 0 )
  142         {
  143           switch ( _PCMD )
  144           {
  145             // Read data
  146             case 0x00:
  147             {
  148               // No input data
  149               if ( _DpaDataLength != 0 )
  150                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  151 
  152               // Copy data to the result, the result length is 16 bytes (one AES block)
  153               copyMemoryBlock( PeripheralRam, _DpaMessage.Response.PData, _DpaDataLength = 16 );
  154               // Encrypt data (_DpaMessage.Response.PData is actually bufferRF)
  155               encryptBufferRF( 1 );
  156               return TRUE;
  157             }
  158 
  159             // Write data
  160             case 0x01:
  161             {
  162               // Exactly one AES block of input data is expected
  163               if ( _DpaDataLength != 16 )
  164                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  165 
  166               // Decrypt data to write (_DpaMessage.Response.PData is actually bufferRF)
  167               decryptBufferRF( 1 );
  168               // Copy written data to the buffer
  169               copyMemoryBlock( _DpaMessage.Request.PData, PeripheralRam, 16 );
  170               // No data is written
  171               _DpaDataLength = 0;
  172               return TRUE;
  173             }
  174 
  175             // Invalid command
  176             default:
  177               DpaApiReturnPeripheralError( ERROR_PCMD );
  178           }
  179         }
  180       }
  181   }
  182 
  183   return FALSE;
  184 }
  185 
  186 //############################################################################################
  187 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 
  188 #include "DPAcustomHandler.h"
  189 //############################################################################################