Крошечный алгоритм шифрования (чай) для произвольного размера данных


Этот чай имеет очень простой алгоритм шифрования, требующий немного времени и пространства - идеально подходит для встраиваемых систем. Есть расширения к ней, и каждая версия имеет свои недостатки (ППР основана на нем), но для повседневной защиты он идеально подходит.

Кроме того, шифровать и расшифровывать процедуры точно из Википедии, так что я не ожидаю, чтобы кто-нибудь проверить, что я после чая правильно - меня больше интересует блок подпрограмм, я добавил, Хотя, если вы заметили что-то о чае процедуры хорошо бы знать.

чай.ч

#ifndef __TEA.H__
#define __TEA.H__

#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k);
void decrypt (uint32_t* v, uint32_t* k);
void encryptBlock(uint8_t * data, uint32_t * len, uint32_t * key);
void decryptBlock(uint8_t * data, uint32_t * len, uint32_t * key);

#endif

чай.с

#include "tea.h"
/* encryptBlock
 *   Encrypts byte array data of length len with key key using TEA
 * Arguments:
 *   data - pointer to 8 bit data array to be encrypted - SEE NOTES
 *   len - length of array
 *   key - Pointer to four integer array (16 bytes) holding TEA key
 * Returns:
 *   data - encrypted data held here
 *   len - size of the new data array
 * Side effects:
 *   Modifies data and len
 * NOTES:
 * data size must be equal to or larger than ((len + 7) / 8) * 8 + 8
 * TEA encrypts in 8 byte blocks, so it must include enough space to 
 * hold the entire data to pad out to an 8 byte boundary, plus another
 * 8 bytes at the end to give the length to the decrypt algorithm.
 *
 *  - Shortcut - make sure that data is at least len + 15 bytes in size.
 */
void encryptBlock(uint8_t * data, uint32_t * len, uint32_t * key)
{
   uint32_t blocks, i;
   uint32_t * data32;

   // treat the data as 32 bit unsigned integers
   data32 = (uint32_t *) data;

   // Find the number of 8 byte blocks, add one for the length
   blocks = (((*len) + 7) / 8) + 1;

   // Set the last block to the original data length
   data32[(blocks*2) - 1] = *len;

   // Set the encrypted data length
   *len = blocks * 8;

   for(i = 0; i< blocks; i++)
   {
      encrypt(&data32[i*2], key);
   }
}

/* decryptBlock
 *   Decrypts byte array data of length len with key key using TEA
 * Arguments:
 *   data - pointer to 8 bit data array to be decrypted - SEE NOTES
 *   len - length of array
 *   key - Pointer to four integer array (16 bytes) holding TEA key
 * Returns:
 *   data - decrypted data held here
 *   len - size of the new data array
 * Side effects:
 *   Modifies data and len
 * NOTES:
 *   None
 */
void decryptBlock(uint8_t * data, uint32_t * len, uint32_t * key)
{
   uint32_t blocks, i;
   uint32_t * data32;

   // treat the data as 32 bit unsigned integers
   data32 = (uint32_t *) data;

   // Find the number of 8 byte blocks
   blocks = (*len)/8;

   for(i = 0; i< blocks; i++)
   {
      decrypt(&data32[i*2], key);
   }

   // Return the length of the original data
   *len = data32[(blocks*2) - 1];
}

/* encrypt
 *   Encrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be encoded in place
 *   k - array of four 32 bit uints to act as key
 * Returns:
 *   v - encrypted result
 * Side effects:
 *   None
 */
void encrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

/* decrypt
 *   Decrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be decoded in place
 *   k - array of four 32 bit uints to act as key
 * Returns:
 *   v - decrypted result
 * Side effects:
 *   None
 */
void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;                                   
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

Пока вопросы:

Кодирование

  • Используя магию чисел в шифрования и дешифрования процедуры - использование директивы #define, а не Кайл
  • Если 64 бит функции кодирования не используются за пределами данного модуля, их прототипы должны быть в коде, а не заголовок - Симон
  • Добавить вменяемость проверить, вход - Роб
  • Требует, чтобы входной сигнал лен кратно 8 байт - установление требования о том, что мы не можем обеспечить или проверить рецепт для коррупции - Роб

Стиль

  • Используя K&Р бандаж стиль в некоторых местах, ANSI, в других - системность - Симон
  • Длинный описательный комментарий полезнее для конечного пользователя, если он находится в заголовке файла (заголовка для использования, код для реализации) - Роб

Редактировать:

Кто-то спросил, для реализации я указал в исходном посте, так вот она. Заметьте, что я не очистил его для презентации.

Для того чтобы расшифровать файл, использовать декодирование файла inputfilename файл outputfilename. Для кодирования файла используется декодирования файла inputfilename файл outputfilename е. Выполнение стандарта ANSI C, поэтому он должен работать в любом месте, хотя сам алгоритм может быть прямой зависимости.

РАСШИФРОВАННЫЙ ФАЙЛ НЕ БУДЕТ СОВПАДАТЬ С ОРИГИНАЛЬНЫМ ФАЙЛОМ. Эта конкретная реализация оставляет количество нулевых байтов в конце расшифрованного файла, которые не присутствовали в оригинале. Для моего приложения это было приемлемо и упрощенный моего конкретного использования, но вы, вероятно, будете нуждаться, чтобы изменить это для вашей пользы.

Он использует фиксированный ключ на 4 линии.

#include <stdio.h>

typedef unsigned long uint32_t;  
const uint32_t TEAKey[4] = {0x95a8882c, 0x9d2cc113, 0x815aa0cd, 0xa1c489f7};

void encrypt (uint32_t* v, const uint32_t* k);
void decrypt (uint32_t* v, const uint32_t* k);

void btea(uint32_t *v, int n, uint32_t const k[4]);

void simpleencrypt(unsigned char * buffer);
void simpledecrypt(unsigned char * buffer);

int main(int argc, char **argv)
{
   FILE *fpin, *fpout;
   int bytecount;
   unsigned char buffer[9], bufferin[9], bufferout[9];
   int i;

   if(argc < 3)
   {
      printf("Use: %s [filenameinput] [filenameoutput]\n", argv[0]);
      return 0;
   }

   if( (fpin = fopen(argv[1], "rb")) == NULL)
   {
      printf("Problem opening input file %s.\n", argv[1]);
      return 0;
   }

   if( (fpout = fopen(argv[2], "wb")) == NULL)
   {
      printf("Problem opening output file %s.\n", argv[2]);
      return 0;
   }

   bytecount = 0;

   while(fread(buffer, 1, 8, fpin) == 8)
   {
      if(argc>3)
      {
            for(i=0;i<8;i++)
            {
                bufferin[i] = buffer[i];
            }

          simpleencrypt(buffer);


            for(i=0;i<8;i++)
            {
                bufferout[i] = buffer[i];
            }
            simpledecrypt(bufferout);
            for(i=0;i<8;i++)
            {
                if(bufferin[i] != bufferout[i])
                {
                    printf("Internal decode test failed.\n");
                }
            }

      }
      else
      {
          simpledecrypt(buffer);
      }
      fwrite(buffer, 1, 8, fpout);
      bytecount+=8;
   }

   if (!feof(fpin))
   {
       printf("Unexpected input file error encountered.\n");
   }

   fclose(fpin); 
   fclose(fpout); 
   printf("%s complete, %i bytes total\n",((argc>3) ? "Encrypt" : "Decrypt"), bytecount);
   return 0;
}

void simpleencrypt(unsigned char * buffer)
{
    uint32_t datablock[2];

    datablock[0] = (buffer[0] << 24) | (buffer[1] << 16)  | (buffer[2] << 8) | (buffer[3]);
    datablock[1] = (buffer[4] << 24) | (buffer[5] << 16)  | (buffer[6] << 8) | (buffer[7]);

    encrypt (datablock, TEAKey);

    buffer[0] = (char) ((datablock[0] >> 24) & 0xFF);
    buffer[1] = (char) ((datablock[0] >> 16) & 0xFF);
    buffer[2] = (char) ((datablock[0] >> 8) & 0xFF);
    buffer[3] = (char) ((datablock[0]) & 0xFF);
    buffer[4] = (char) ((datablock[1] >> 24) & 0xFF);
    buffer[5] = (char) ((datablock[1] >> 16) & 0xFF);
    buffer[6] = (char) ((datablock[1] >> 8) & 0xFF);
    buffer[7] = (char) ((datablock[1]) & 0xFF);
}

void simpledecrypt(unsigned char * buffer)
{
    uint32_t datablock[2];

    datablock[0] = (buffer[0] << 24) | (buffer[1] << 16)  | (buffer[2] << 8) | (buffer[3]);
    datablock[1] = (buffer[4] << 24) | (buffer[5] << 16)  | (buffer[6] << 8) | (buffer[7]);

    decrypt (datablock, TEAKey);

    buffer[0] = (char) ((datablock[0] >> 24) & 0xFF);
    buffer[1] = (char) ((datablock[0] >> 16) & 0xFF);
    buffer[2] = (char) ((datablock[0] >> 8) & 0xFF);
    buffer[3] = (char) ((datablock[0]) & 0xFF);
    buffer[4] = (char) ((datablock[1] >> 24) & 0xFF);
    buffer[5] = (char) ((datablock[1] >> 16) & 0xFF);
    buffer[6] = (char) ((datablock[1] >> 8) & 0xFF);
    buffer[7] = (char) ((datablock[1]) & 0xFF);
}

/* encrypt
 *   Encrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be encoded in place
 *   k - array of four 32 bit uints to act as key
 * Returns:
 *   v - encrypted result
 * Side effects:
 *   None
 */
void encrypt (uint32_t* v, const uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

/* decrypt
 *   Decrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be decoded in place
 *   k - array of four 32 bit uints to act as key
 * Returns:
 *   v - decrypted result
 * Side effects:
 *   None
 */
void decrypt (uint32_t* v, const uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;                                   
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

#define DELTA 0x9e3779b9
  #define MX ((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (k[(p&3)^e] ^ z));

  void btea(uint32_t *v, int n, uint32_t const k[4]) {
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1) {          /* Coding Part */
      rounds = 6 + 52/n;
      sum = 0;
      z = v[n-1];
      do {
        sum += DELTA;
        e = (sum >> 2) & 3;
        for (p=0; p<n-1; p++)
          y = v[p+1], z = v[p] += MX;
        y = v[0];
        z = v[n-1] += MX;
      } while (--rounds);
    } else if (n < -1) {  /* Decoding Part */
      n = -n;
      rounds = 6 + 52/n;
      sum = rounds*DELTA;
      y = v[0];
      do {
        e = (sum >> 2) & 3;
        for (p=n-1; p>0; p--)
          z = v[p-1], y = v[p] -= MX;
        z = v[n-1];
        y = v[0] -= MX;
      } while ((sum -= DELTA) != 0);
    }
  }


20329
27
задан 6 сентября 2008 в 10:09 Источник Поделиться
Комментарии
5 ответов

Вы должны добавить некоторые проверки работоспособности на входящие аргументы, особенно если вы предназначаете это, чтобы быть библиотека код используется несколькими проектами.

Я бы порекомендовал вам изменить определение encryptBlock, чтобы требовать , что лен кратно 8 байт. Требуя, чтобы входной массив размера до кратного 8 байтам, но не навязывая, что лен-это верный способ получить повреждению памяти, когда кто-то забывает (например, когда они шифрование строк).

Лично я предпочитаю иметь длинные описательные комментарии в заголовке файла, а не .файл c. Кто-нибудь используя чай.ч найдете его более полезным там.

10
ответ дан 6 сентября 2008 в 11:09 Источник Поделиться

Реализации шифров, как оптимизация: первое правило: "не делай этого". Оставьте это специалистам, ведь существует множество важных деталей, которые вы пропустите, если вы не эксперт.

Три вещи, которые выпрыгивают на меня из-за этого:


  1. Кофеварка сломана. Это не "идеальный" для "повседневная защита". Его преемники также разбито, и я лично бы не использовать любой из них, но, по крайней мере, они меньше ломаются.

  2. Обивка-это несколько нетрадиционно, и гарантий требуют дополнительную полуквартале. Есть несколько подходов , которые требуют дополнительный блок только тогда, когда сообщение является неотъемлемой количество блоков в длину.

  3. Единственный режим работы поддерживается ЕЦБ. Это большой красный флаг. Вопрос какой блок режим лучше пока не урегулирован, но ЕЦБ, безусловно, самое худшее.

7
ответ дан 16 октября 2012 в 09:10 Источник Поделиться

Не глядя слишком близко, я борюсь, чтобы увидеть каких-либо серьезных проблем с этим кодом. Вот несколько тривиальных вопросов:


  1. Ты имел в виду, чтобы использовать различные стили бандажа? Блок использовать функции (вроде) к&подтяжки R и 64-битные функции использование ANSI брекеты.

  2. Представлены 64-битные функции либо для использования вне модуля? Если нет, я бы переместить их прототипов .файл c.

5
ответ дан 6 сентября 2008 в 10:09 Источник Поделиться

Я вообще-то наоборот, если Роб Уокер в том, что я предпочитаю там быть хороший комментарий блок, предшествующий функции в код файла в отличие от заголовка. Однако, как долго, как вы постоянны в том, где вы положили ваши комментарии, большинство людей не имеют проблему, если это не идет против руководство вашей компании Стиль. Единственная вещь я могу думать о с точки зрения стиля будет блок комментариев в начале файла с некоторыми общими сведениями, например:


/*-----------------------------------------------------------------------------
* Файл -
* Автор(ы) -
*
* Цель -
*
*-----------------------------------------------------------------------------
* Примечания -
*-----------------------------------------------------------------------------
* Изменения -
*---------------------------------------------------------------------------*/

Иногда вы также увидите информацию об авторском праве в эти блоки. Это просто пример того, что один, хотя похоже.

С точки зрения самого кода, я должен согласиться с другим в отношении сдачи "магических чисел" в сторону и убедившись, что они четко обозначены, что они делают. Так же для проверки работоспособности, если это будет использоваться как часть библиотеки.

5
ответ дан 8 сентября 2008 в 01:09 Источник Поделиться

Я не знакома с вашим алгоритмом, но взглянув на ваш код, похоже, суммы и дельты магических чисел. Поскольку Дельта распределяется между шифрования и дешифрования, это может быть хорошей идеей, чтобы #их определить в верхней части файла.

редактировать: я только что посмотрел статью в Википедии и магические числа в эталонной реализации, который был дословно скопирован в код.

4
ответ дан 6 сентября 2008 в 10:09 Источник Поделиться