TEA是一种非常简单的加密算法,几乎不需要时间和空间,非常适合嵌入式系统。它有扩展,每个版本都有其缺陷(WEP就是基于它的),但是对于临时保护它是完美的。

此外,加密和解密例程也与Wikipedia完全相同,因此我不希望有人检查我是否正确地遵循了TEA-我对我添加的块例程更感兴趣,尽管如果您注意到有关TEA例程的信息,那将是一个很好的了解。 >
tea.h

#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


tea.c

#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;
}


目前为止问题:

编码


在加密和解密例程中使用幻数-改为使用#defines-Kyle
如果未在外部使用64位编码功能此模块,其原型应在代码中,而不在标头中-Simon
向输入添加健全性检查-Rob
要求输入len为8字节的倍数-要求我们无法执行或支票是腐败的秘诀-Rob

样式


使用K&R大括号样式在某些地方,在其他地方则是ANSI-一致性-Simon
如果描述头文件中的长描述性注释(位于标头文件中,用于用法,实现代码)对于最终用户更为有用-Rob


编辑:

有人要求我在原始帖子中指出的实现,就在这里。请注意,我尚未将其清理以进行演示。

要解码文件,请使用decode inputfilename outputfilename。要编码文件,请使用decode inputfilename outputfilename e。 ANSI C实现,因此尽管算法本身可能依赖于字节序,但它仍可在任何地方工作。

已解密的文件将不完全匹配原始文件。此特定实现在原始文件中不存在的解密文件的末尾留下了许多空字节。对于我的应用程序来说,这是可以接受的,并简化了我的特定用法,但是您可能需要对其进行修改以供使用。 >
#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);
    }
  }


评论

您介意以下内容:1.“指向8位数据数组的指针”是什么意思?这是否意味着数据只能被8位读取一次? 2.在您的实现中显示4个固定键,但是可以在文件中随机选择4个键吗?

@LimTeikWei它只需要一个指向数据的指针。它将数据视为字节数组。是的,四个键可以是您喜欢的任何数字。

作为参考,这是TEA的电子密码本扩展。因此,它仅应用于小型和/或永不重复的数据。

看来这是Code Review上最古老的问题。不错!

什么是“临时保护”?保护或不保护。坏掉的加密比没用还糟。

#1 楼

您应该在传入的参数上添加一些完整性检查,尤其是如果您打算将其用作多个项目中的库代码。个字节。要求传入数组的大小为8字节的倍数,但不强制为len是肯定的有效方法,当有人忘记时(例如,他们在加密字符串时),它会导致内存损坏。我更喜欢在头文件中而不是.c文件中包含较长的描述性注释。任何使用tea.h的人都会在这里发现它更有用。

评论


\ $ \ begingroup \ $
对于某些要加密的内容,我将要求输入为8字节的倍数,因此感谢您的建议!
\ $ \ endgroup \ $
–亚当·戴维斯(Adam Davis)
08-09-15 at 12:45

\ $ \ begingroup \ $
也许更重要的是,您应该对输出进行完整性检查。当前没有检查来验证cryptoBlock的输出长度是否≤输入长度。这是一个等待发生的缓冲区过度利用漏洞。
\ $ \ endgroup \ $
–传真
19-09-13在10:35



#2 楼

实施密码就像是优化:第一个规则是“不要这样做”。留给专家,因为如果您不是专家,您会遗漏许多重要的细节。 />
TEA坏了。对于“临时保护”而言,它不是“完美”的。它的后继者也坏了,我个人也不会使用它们,但至少它们没有那么坏。有几种方法仅在消息的长度为整数个块时才需要额外的块。
唯一支持的操作模式是ECB。这是一个很大的危险信号。哪种块模式最好的问题尚未解决,但欧洲央行无疑是最差的。

评论


\ $ \ begingroup \ $
它的一个重要优点是,它不仅非常自由地在美国以外的地区免费提供,而且即使在微型微控制器上,它也简单,快速。是的,相对于密钥长度而言,它是不安全的,但是在许多应用程序中,它是足够安全的,并且较低的处理要求有时使其成为值得的选择。但是,在大多数高级处理器上,高级指令集包括对密码学友好的运算符,甚至高级加密也不需要比tea强大的功能,如果许可条款可接受,则应使用它们。
\ $ \ endgroup \ $
–亚当·戴维斯(Adam Davis)
2012年10月16日23:19



#3 楼

不必太仔细地看,我正在努力查看此代码的任何主要问题。以下是几个琐碎的问题:


您是要使用不同的花括号样式吗?块函数使用K&R大括号(某种),而64位函数使用ANSI大括号。
64位函数是否曾经在模块外部使用?如果没有,我将其原型移至.c文件。


#4 楼

如果与Rob Walker相反,我实际上是相反的,因为我更喜欢在代码文件中的函数之前而不是标头之前有一个漂亮的注释块。但是,只要您坚持发表意见的方式,大多数人就不会有问题,除非这与您公司的风格手册相抵触。就样式而言,我唯一想到的另一件事是文件开头的注释块,其中包含一些常规信息,例如:
也将在这些块中看到版权信息。这只是一个人看起来像的例子。

就代码本身而言,在将“魔术数字”放在一边并确保其正确性方面,我必须与其他人达成共识。他们清楚地标明了他们的工作。同理检查是否将其用作库的一部分。

#5 楼

我对您的算法不熟悉,但是浏览一下您的代码,看起来sum和delta是幻数。由于delta是在加密和解密之间共享的,因此最好在文件顶部#define定义它们。在参考实现中,已逐字复制到您的代码中。