Generalnie w szyfrowaniu i deszyfrowaniu występuje pojęcie klucza. W przypadku szyfrowania jest to dodatkowa informacja, która jest użyta do zaszyfrowania danych, czyli zastąpienia danych, które podlegają ochronie innymi danymi sprawiającymi wrażenie danych przypadkowych. W deszyfrowaniu potrzebny jest właściwy klucz, bez znajomości którego odtworzenie oryginalnych danych jest niemożliwe. Klucz do zaszyfrowania i odszyfrowania może być identyczny, wtedy mamy przypadek klucza symetrycznego.
DES jest szyfrem blokowym z blokami o długości 64 bitów (czyli 8 bajtów). Do szyfrowania i deszyfrowania danych wykorzystywanych jest 56 bitów klucza (klucz jest symetryczny), który zapisany jest w postaci 64 bitowego ciągu, w którym co 8 bit jest bitem kontrolnym i może służyć do kontroli parzystości. W szyfrowaniu tym algorytmem dane jawne są dzielone na bloki 64-bitowe (po 8 bajtów), które są później przetwarzane. Algorytm 3DES jest modyfikacją algorytmu podstawowego DES. Wykorzystuje ona do szyfrowania i deszyfrowania trzy klucze. Najpierw wiadomość jest szyfrowana pierwszym kluczem, następnie deszyfrowana drugim i ponownie szyfrowana trzecim kluczem. Koncepcyjnie można uznać, że algorytm 3DES jest algorytmem DES z kluczem trzy razy większym, czyli ma 192-bitowy klucz (jako 24 bajty).
W przypadku mikrokontrolerów AVR algorytmu 3DES można użyć przykładowo do ochrony zawartości pamięci EEPROM lub do szyfrowania transmisji poprzez UART. Poniższy program prezentuje „obróbkę” bloku danych polegającą na:
- wyświetleniu zawartości bloku danych przed zaszyfrowaniem,
- wyświetlenie zawartości bloku danych po zaszyfrowaniu,
- wyświetlenie zawartości bloku danych po odszyfrowaniu.
Środowisko sprzętowe eksperymentu jest następujące:
Tekst programu prezentacyjnego:
Kod: Zaznacz cały
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "descrypto.h"
#define LEDPort PORTB
#define LEDDirPort DDRB
#define Cr 0x0D
#define Lf 0x0A
#define USART_Speed 47 // USART BAUD Rate Generator fosc=7.3728 MHz , 9600 bps
#define StandardTimerDelay 24
#define nop() __asm__ __volatile__ ("nop")
#define IdleState 0
#define BusyState 1
#define TXDBuffSize 16
#define RXDBuffSize 16
typedef struct { uint8_t CycFr ;
uint8_t CycTo ;
uint8_t State ;
uint8_t Buffer [ TXDBuffSize ] ;
} TXDRecT ;
typedef struct { uint8_t CycFr ;
uint8_t CycTo ;
uint8_t Buffer [ RXDBuffSize ] ;
} RXDRecT ;
static volatile TXDRecT TXDRec ;
static volatile RXDRecT RXDRec ;
static uint8_t TimerCounter ;
static uint8_t LEDData ;
static DES3InstanceType DES3Instance ;
static uint8_t CryptKey [ 24 ] ;
static uint8_t HelloTxt [ ] PROGMEM = "\r\nHello:\r\nPrezentacja szyfrowania algorytmem 3DES\r\n" ;
SIGNAL ( TIMER0_OVF_vect )
{
/*-------------------------------------------------------------------------*/
TimerCounter ++ ;
if ( TimerCounter > StandardTimerDelay )
{
TimerCounter = 0 ;
LEDData ++ ;
LEDPort = LEDData ;
} /* if */ ;
} /* TIMER0_OVF_vect */
SIGNAL ( SIG_UART_RECV )
{
uint8_t RecVCh ;
/*-------------------------------------------------------------------------*/
RecVCh = UDR ;
RXDRec . Buffer [ RXDRec . CycTo ] = RecVCh ;
RXDRec . CycTo ++ ;
if ( RXDRec . CycTo >= RXDBuffSize )
RXDRec . CycTo = 0 ;
} /* SIG_USART_RECV */
SIGNAL ( SIG_UART_TRANS )
{
/*-------------------------------------------------------------------------*/
if ( TXDRec . CycFr == TXDRec . CycTo )
{
TXDRec . State = IdleState ;
} /* if ... */
else
{
UDR = TXDRec . Buffer [ TXDRec . CycFr ] ;
TXDRec . CycFr ++ ;
if ( TXDRec . CycFr >= TXDBuffSize )
TXDRec . CycFr = 0 ;
} /* if ... else */ ;
} /* SIG_USART_TRANS */
static void USARTSoftwareInit ( void )
{
/*-------------------------------------------------------------------------*/
RXDRec . CycFr = 0 ;
RXDRec . CycTo = 0 ;
TXDRec . CycFr = 0 ;
TXDRec . CycTo = 0 ;
TXDRec . State = IdleState ;
} /* USARTSoftwareInit */
static void SendSerial ( uint8_t SerialCh )
{
uint8_t NextInx ;
/*-------------------------------------------------------------------------*/
cli ( ) ;
if ( TXDRec . State == IdleState )
{
TXDRec . State = BusyState ;
UDR = SerialCh ;
sei ( ) ;
} /* if ... */
else
{
for ( ; ; )
{
NextInx = TXDRec . CycTo + 1 ;
if ( NextInx >= TXDBuffSize )
NextInx = 0 ;
if ( NextInx != TXDRec . CycFr )
break ;
sei ( ) ;
nop ( ) ;
nop ( ) ;
cli ( ) ;
} /* for */ ;
TXDRec . Buffer [ TXDRec . CycTo ] = SerialCh ;
TXDRec . CycTo ++ ;
if ( TXDRec . CycTo >= TXDBuffSize )
TXDRec . CycTo = 0 ;
sei ( ) ;
} /* if ... else */ ;
} /* SendSerial */
static void SendSerialFlashTxt ( uint16_t String )
{
uint8_t Data ;
/*-------------------------------------------------------------------------*/
for ( ; ; )
{
Data = pgm_read_byte_near ( String ) ;
if ( Data )
SendSerial ( Data ) ;
else
break ;
String ++ ;
} /* for */ ;
} /* SendSerialFlashTxt */
static void HardwareInit ( void )
{
/*-------------------------------------------------------------------------*/
TIMSK = ( 1 << TOIE0 ) ; // Timer/counter Interrupt Mask
// TOIE0: Timer/Counter0 Overflow Interrupt Enable
TCCR0 = ( 1 << CS02 ) ; // Timer/Counter Control Register
// CS00: Clock Select
// CS01: Clock Select
// CS02: Clock Select
UCSRA = 0 ;
UCSRB = ( 1 << RXCIE ) | ( 1 << TXCIE ) | ( 1 << RXEN ) | ( 1 << TXEN ) ;
// USART Control and Status Register B
// TXEN : Transmitter Enable
// RXEN : Receiver Enable
// TXCIE : TX Complete Interrupt Enable
// RXCIE : RX Complete Interrupt Enable
UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ) ;
// UART Control and Status Register C
// UCSZ0 : USART Character Size
// UCSZ1 : USART Character Size
// URSEL : USART Register Select
UBRRH = ( uint8_t ) ( ( USART_Speed >> 8 ) & 0xFF ) ;
UBRRL = ( uint8_t ) ( USART_Speed & 0xFF ) ;
} /* HardwareInit */
static void EnvironmentInit ( void )
{
/*-------------------------------------------------------------------------*/
LEDDirPort = 0xFF ;
LEDPort = 0 ;
} /* EnvironmentInit */
static void SoftwareInit ( void )
{
/*-------------------------------------------------------------------------*/
USARTSoftwareInit ( ) ;
TimerCounter = 0 ;
LEDData = 0 ;
CryptKey [ 0 ] = 'K' ;
CryptKey [ 1 ] = 'l' ;
CryptKey [ 2 ] = 'u' ;
CryptKey [ 3 ] = 'c' ;
CryptKey [ 4 ] = 'z' ;
CryptKey [ 5 ] = ' ' ;
CryptKey [ 6 ] = 'd' ;
CryptKey [ 7 ] = 'o' ;
CryptKey [ 8 ] = ' ' ;
CryptKey [ 9 ] = 's' ;
CryptKey [ 10 ] = 'y' ;
CryptKey [ 11 ] = 'f' ;
CryptKey [ 12 ] = 'r' ;
CryptKey [ 13 ] = 'o' ;
CryptKey [ 14 ] = 'w' ;
CryptKey [ 15 ] = 'a' ;
CryptKey [ 16 ] = 'n' ;
CryptKey [ 17 ] = 'i' ;
CryptKey [ 18 ] = 'a' ;
CryptKey [ 19 ] = '.' ;
CryptKey [ 20 ] = 0 ;
CryptKey [ 21 ] = 0 ;
CryptKey [ 22 ] = 0 ;
CryptKey [ 23 ] = 0 ;
} /* SoftwareInit */
void WordToStr ( uint8_t * Cnv ,
uint8_t ConvWidth ,
uint8_t EmptyCh ,
uint16_t Value )
{
uint8_t Loop ;
/*-------------------------------------------------------------------------*/
for ( Loop = 0 ; Loop < ConvWidth ; Loop ++ )
* ( Cnv + Loop ) = EmptyCh ;
* ( Cnv + ConvWidth ) = ( uint8_t ) 0 ;
Loop = ConvWidth - 1 ;
for ( ; ; )
{
* ( Cnv + Loop ) = ( uint8_t ) ( ( Value % 10 ) + '0' ) ;
Value /= 10 ;
if ( ( ! Loop ) || ( ! Value ) )
break ;
Loop -- ;
} /* for */ ;
} /* WordToStr */
void LoadCryptKey ( void )
{
uint8_t * DES3_keys0 ;
uint8_t * DES3_keys1 ;
uint8_t * DES3_keys2 ;
/*-------------------------------------------------------------------------*/
DES3_keys0 = & CryptKey [ 0 ] ;
DES3_keys1 = & CryptKey [ 8 ] ;
DES3_keys2 = & CryptKey [ 16 ] ;
des3_set_3keys ( & DES3Instance , DES3_keys0 , DES3_keys1 , DES3_keys2 ) ;
} /* LoadCryptKey */
void TraceBuffer ( uint8_t * BuffToPrint ,
uint8_t BuffSize )
{
uint8_t Loop;
uint8_t Data ;
uint8_t Number [ 8 ] ;
uint8_t * Buff ;
/*-------------------------------------------------------------------------*/
Buff = BuffToPrint ;
for ( Loop = 0 ; Loop < BuffSize ; Loop ++ )
{
Data = * Buff ++ ;
SendSerial ( ' ' ) ;
SendSerial ( ' ' ) ;
if ( Data < 32 )
SendSerial ( '.' ) ;
else
SendSerial ( Data ) ;
SendSerial ( ' ' ) ;
} /* for */ ;
SendSerial ( Cr ) ;
SendSerial ( Lf ) ;
Buff = BuffToPrint ;
for ( Loop = 0 ; Loop < BuffSize ; Loop ++ )
{
Data = * Buff ++ ;
WordToStr ( Number , 3 , ' ' , ( uint16_t ) Data ) ;
SendSerial ( Number[0] ) ;
SendSerial ( Number[1] ) ;
SendSerial ( Number[2] ) ;
SendSerial ( ' ' ) ;
} /* for */ ;
SendSerial ( Cr ) ;
SendSerial ( Lf ) ;
} /* TraceBuffer */
static uint8_t Text1 [ ] PROGMEM = "\r\nKlucz szyfrujacy: " ;
static uint8_t Text2 [ ] PROGMEM = "\r\nDane przed szyfrowaniem:\r\n" ;
static uint8_t Text3 [ ] PROGMEM = "\r\nDane po szyfrowaniu:\r\n" ;
static uint8_t Text4 [ ] PROGMEM = "\r\nDane po odszyfrowaniu:\r\n" ;
void DES3_Test ( void )
{
uint8_t InputBuff [ 20 ] ;
uint8_t OutputBuff [ 20 ] ;
uint8_t Loop ;
int StrLgt ;
/*-------------------------------------------------------------------------*/
SendSerial ( Cr ) ;
SendSerial ( Lf ) ;
SendSerialFlashTxt ( ( uint16_t ) Text1 ) ;
SendSerial ( '<' ) ;
for ( Loop = 0 ; Loop < 24 ; Loop ++ )
{
if ( CryptKey [ Loop ] < 32 )
SendSerial ( '.' ) ;
else
SendSerial ( CryptKey [ Loop ] ) ;
} /* for */ ;
SendSerial ( '>' ) ;
SendSerial ( Cr ) ;
SendSerial ( Lf ) ;
InputBuff[0]='L';
InputBuff[1]='i';
InputBuff[2]='t';
InputBuff[3]='w';
InputBuff[4]='o';
InputBuff[5]=' ';
InputBuff[6]='o';
InputBuff[7]='j';
InputBuff[8]='c';
InputBuff[9]='z';
InputBuff[10]='y';
InputBuff[11]='z';
InputBuff[12]='n';
InputBuff[13]='o';
InputBuff[14]=' ';
InputBuff[15]='m';
InputBuff[16]='o';
InputBuff[17]='j';
InputBuff[18]='a';
InputBuff[19]='.';
StrLgt = 20 ;
SendSerialFlashTxt ( ( uint16_t ) Text2 ) ;
TraceBuffer ( InputBuff , StrLgt ) ;
EncryptString ( & DES3Instance , InputBuff , OutputBuff , StrLgt ) ;
SendSerialFlashTxt ( ( uint16_t ) Text3 ) ;
TraceBuffer ( OutputBuff , StrLgt ) ;
DecryptString ( & DES3Instance , OutputBuff , InputBuff , StrLgt ) ;
SendSerialFlashTxt ( ( uint16_t ) Text4 ) ;
TraceBuffer ( InputBuff , StrLgt ) ;
} /* DES3_Test */
int main ( void )
{
/*-------------------------------------------------------------------------*/
HardwareInit ( ) ;
EnvironmentInit ( ) ;
SoftwareInit ( ) ;
sei ( ) ;
LoadCryptKey ( ) ;
DES3_Test ( ) ;
for ( ; ; )
{
nop ( ) ;
} /* for */ ;
return ( 0 ) ;
} /* main */
Istotne elementy w programie:
static void SoftwareInit ( void )
{
...
CryptKey [ 0 ] = 'K' ;
CryptKey [ 1 ] = 'l' ;
CryptKey [ 2 ] = 'u' ;
CryptKey [ 3 ] = 'c' ;
CryptKey [ 4 ] = 'z' ;
CryptKey [ 5 ] = ' ' ;
CryptKey [ 6 ] = 'd' ;
CryptKey [ 7 ] = 'o' ;
CryptKey [ 8 ] = ' ' ;
CryptKey [ 9 ] = 's' ;
CryptKey [ 10 ] = 'y' ;
CryptKey [ 11 ] = 'f' ;
CryptKey [ 12 ] = 'r' ;
CryptKey [ 13 ] = 'o' ;
CryptKey [ 14 ] = 'w' ;
CryptKey [ 15 ] = 'a' ;
CryptKey [ 16 ] = 'n' ;
CryptKey [ 17 ] = 'i' ;
CryptKey [ 18 ] = 'a' ;
CryptKey [ 19 ] = '.' ;
CryptKey [ 20 ] = 0 ;
CryptKey [ 21 ] = 0 ;
CryptKey [ 22 ] = 0 ;
CryptKey [ 23 ] = 0 ;
} /* SoftwareInit */
Jako klucz należy wypełnić każdy bajt jego obszaru (w sumie 24 bajty - klucz 192-bitowy).
void DES3_Test ( void )
{
...
InputBuff[0]='L';
InputBuff[1]='i';
InputBuff[2]='t';
InputBuff[3]='w';
InputBuff[4]='o';
InputBuff[5]=' ';
InputBuff[6]='o';
InputBuff[7]='j';
InputBuff[8]='c';
InputBuff[9]='z';
InputBuff[10]='y';
InputBuff[11]='z';
InputBuff[12]='n';
InputBuff[13]='o';
InputBuff[14]=' ';
InputBuff[15]='m';
InputBuff[16]='o';
InputBuff[17]='j';
InputBuff[18]='a';
InputBuff[19]='.';
...
} /* DES3_Test */
Jako przykład jest podany tekst (jako łańcuch znaków). W ogólnym przypadku funkcje szyfrowania i deszyfrowania traktują dane wejściowe jako blok w pamięci RAM, dlatego w tych funkcjach podawana jest długość bloku wyrażona w bajtach (nie istnieje coś takiego jak znak końca danych występujący w przetwarzaniu stringów).
W dołączonym do programu prezentującego module zawierającym funkcje szyfrowania i deszyfrowania znajdują się:
Kod: Zaznacz cały
typedef struct {
uint32_t esk [ 96 ] ; /* Triple-DES encryption subkeys */
uint32_t dsk [ 96 ] ; /* Triple-DES decryption subkeys */
} DES3InstanceType ;
extern int des3_set_3keys ( DES3InstanceType * DES3Instance ,
uint8_t key1 [ 8 ] ,
uint8_t key2 [ 8 ] ,
uint8_t key3 [ 8 ] ) ;
extern void EncryptString ( DES3InstanceType * DES3Instance ,
unsigned char * Inp ,
unsigned char * Out ,
int StrLgt ) ;
extern void DecryptString ( DES3InstanceType * DES3Instance ,
unsigned char * Inp ,
unsigned char * Out ,
int StrLgt ) ;
DES3InstanceType to struktura obszaru danych w pamięci RAM używanej w module szyfrująco/deszyfrującym. Każde użycie funkcji szyfrującej/deszyfrującej wymaga podania wskaźnika do takiego obszaru. Przed pierwszym użyciem należy ten obszar zainicjować poprzez wywołanie funkcji des3_set_3keys, która jest jednocześnie załadowaniem klucza (jako trzech kluczy 64-bitowych). Obszar każdego klucza musi zawierać 8 bajtów ustalonego klucza.
Funkcja EncryptString służy do zaszyfrowania obszaru Inp o długości StrLgt a wynik szyfrowania jest umieszczony w obszarze Out.
Funkcja DecryptString służy do odszyfrowania obszaru Inp o długości StrLgt a wynik deszyfrowania jest umieszczony w obszarze Out.
Załącznik (projekt w AVRSTUDIO):