泰皇娱乐从做题到出题再到做题三部曲-TEA(下)_偃师民声网

泰皇娱乐

前言

这次来了解下Tea的改进版,xTea和xxTea

xTea

原理图:

来自wiki的介绍

翻译过来就是:

在密码学中,XTEA(扩展TEA)是一种用于纠正TEA弱点的分组密码。该密码的设计师是大卫·惠勒和罗杰·尼达姆的的剑桥大学计算机实验室,该算法在未公开的技术报告,1997年(李约瑟和惠勒,1997)提出的。它不受任何专利的约束。[1]  与TEA一样,XTEA是一个64位块 Feistel密码,具有128位密钥和建议的64轮。与TEA的一些差异是显而易见的,包括更复杂的关键时间表以及轮班,异或和补充的重新安排。

C代码如下:

/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */  void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;     for (i=0; i < num_rounds; i++) {         v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);         sum += delta;         v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);     }     v[0]=v0; v[1]=v1; }  void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;     for (i=0; i < num_rounds; i++) {         v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);         sum -= delta;         v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);     }     v[0]=v0; v[1]=v1; } 

说了那么多,反正我对密码学的东西一窍不通,只知道和Tea存在不同就是了,所以。盘它就完事了!

从代码上可以看到和tea相比多了一个参数num_rounds,以及计算的方式发生了变化,其实我感觉和tea差不多,都是左移4位,右移5位。

v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); sum += delta; v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);

解题

题目代码都差不多,放在文末

我们直接开始盘它,在进encrypt之前看一下参数

rsi

rdi

注意到参数有三,跟进、下断,运行,循环。

循环位置如下:

这次循环的位置就不是非常容易观察出来。

可以看到主要的操作,多了一些有意思的东西。

<<4 >>5 xor 3 <<4 >>5 >>11 xor 3

一轮循环之后,通过观察比对数据,可以总结出以下特征:

  1. 一个特征量0x9E3779B9
  2. key 128 bit
  3. enc 64 bit
  4. 一个num_round控制循环次数
  5. 4,5,11,3特征操作值

解题脚本在文末

xxTea

原理图:

具体介绍参考

字有点多懒的复制了

C代码如下:

#include <stdint.h>   #define DELTA 0x9e3779b9   #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))    void btea(uint32_t *v, int n, uint32_t const key[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;         sum -= DELTA;       } while (--rounds);     }   } 

将n个字编码或解码为单个块,其中n > 1
一些参数含义如下:

  1. v是n字数据向量
  2. k是4字密钥
  3. n是v长度的绝对值 大于0为编码 解码时取反
  4. 如果n为零,则结果为1,不进行编码或解码,否则结果为零
    假定32位“长”和相同的字节序编码和解码

xxTea的加解密是通过参数来进行控制的,因此看代码时只需要关注其一半即可

解题

基础的不说了直接跟进cyrpt部分

先是n和1进行比较

rounds = 6 + 52/n;
根据n算出rounds,其中的mov ecx 34h和add ecx 6都很明显

右移2位并且异或3

在汇编里看起来很明显,咱们F5试一下?

顿时一愣!还是看汇编清楚。

继续往下,可以看到和tea&xtea算法类似的操作:

>>5 <<2 >>3 <<4 xor 3

其中有两层循环一个是rounds次,一个是n-1
所以总结特征如下:

1. key 128 bit 2. enc => 32*i(i=>2) 3. 特征量`0x9e3779b9` 4. 两层循环,通常记住最外层的循环为rounds=6+52/n 5. 5,2,3,4左右移操作

注意一点xxTea的加密数据最少是64位,长度是可以任意的(32*i)。

总结

Tea&xTea&xxTea

这次学完了这个系列的算法,来总结一下,不要弄混淆了。

相同点:

  1. key 128 bit(当然还有很多算法的key=128bit)
  2. 特征量0x9e3779b9
  3. 主要加密部分进行移位和异或操作

首先如果题目中出现常量0x9e3779b9,那么肯定是Tea相关算法了。

区分:

  1. Tea的主加密部分为<<4,>>5,xor,循环32轮
  2. xTea的主加密部分<<4,>>5,>>11,xor,循环次数不定,但通常也为32轮,需要传入3个参数
  3. xxTea的主加密部分>>5,<<2,>>3,<<4,xor,循环次数为6+52/n,enc长度大于64

我想拿这三者结合起来,魔改一下,出个题,看看自己到底掌握了没有。

腾讯的加密算法是16轮的Tea算法

题目代码和解题代码

说明:在上一篇的解题脚本中出现了一点错误,现修正如下,其实是格式化输出的问题。

printf("flag{%x-%x}\n",flagLong[0],flagLong[1]);  修改为  printf("flag{%X-%.08X}\n",flagLong[0],flagLong[1]);

xTea题目:

#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdbool.h>  /* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */  void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;     for (i=0; i < num_rounds; i++) {         v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);         sum += delta;         v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);     }     v[0]=v0; v[1]=v1; }  void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;     for (i=0; i < num_rounds; i++) {         v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);         sum -= delta;         v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);     }     v[0]=v0; v[1]=v1; }   int getStr(char *buffer,int maxLen){     char c;  // 读取到的一个字符     int len = 0;  // 当前输入的字符串的长度     // 一次读取一个字符,保存到buffer     // 直到遇到换行符(\n),或者长度超过maxLen时,停止读取     while( (c=getchar()) != '\n' ){         buffer[len++]=c;  // 将读取到的字符保存到buffer         if(len>=maxLen){             break;         }     }     buffer[len]='\0';  // 读取结束,在末尾手动添加字符串结束标志     fflush(stdin);  // 刷新输入缓冲区     return len; }  /*将大写字母转换成小写字母*/   int tolower(int c)   {       if (c >= 'A' && c <= 'Z')       {           return c + 'a' - 'A';       }       else       {           return c;       }   }   //将十六进制的字符串转换成整数   int htoi(char s[])   {       int i = 0;       int n = 0;       if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))       {           i = 2;       }       else       {           i = 0;       }       for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i)       {           if (tolower(s[i]) > '9')           {               n = 16 * n + (10 + tolower(s[i]) - 'a');           }           else           {               n = 16 * n + (tolower(s[i]) - '0');           }       }       return n;   }   void reverse(char *s, int start, int end) {      char t;      while(end>start){         t=s[start];          s[start]=s[end];          s[end]=t;         start++;          end--;      }   }  int main() {     uint32_t v[2]={1,2},k[4]={2,2,3,4};     // v为要加密的数据是两个32位无符号整数     // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位     int flagLen = 0;     bool success = false;     char flag[33];     memset(flag, 0, sizeof(flag));//清空字符串     setbuf(stdin,0);     setbuf(stdout,0);     setbuf(stderr,0);      printf("Please input you flag:");     flagLen = getStr(flag,32);      //check formant     uint8_t vv[5] = {0};     strncpy(vv,flag,4);     uint8_t five = 123;     uint8_t last = 125;     uint8_t *v1,*v2;     if(((uint8_t)flag[5] - five)>0){         printf("five error!");         return -1;     }      if(((uint8_t)flag[flagLen-1] + last) == 250){         ;     }else{         printf("last error!");         return -1;     }      if(strcmp(vv,"flag")){         printf("header error!");         return -1;     }     int mallocSize = flagLen - 6;     char *tokstr = (char *)malloc(sizeof(char)*mallocSize+1);     memset(tokstr, 0, sizeof(tokstr));//清空字符串     strncpy(tokstr,flag+5,mallocSize);      v1 = strtok(tokstr,"-");      v2 = strtok(NULL,"-");      //exchange scale     uint32_t flagLong[2];     flagLong[0] = (uint32_t)htoi((char *)v1);     flagLong[1] = (uint32_t)htoi((char *)v2);     // printf("%d",sizeof(int));  4 byte == 32 bit      // printf("加密前原始数据:%x %x\n",flagLong[0],flagLong[1]);     encipher(32,flagLong, k);     // printf("加密后的数据:%x %x\n",flagLong[0],flagLong[1]);     // check flag     uint8_t check_enc[4];     uint8_t check_index[4] = {3,1,0,2};     uint8_t i=0;     check_enc[0] = 0x8c;     check_enc[1] = 0xa2;     check_enc[2] = 0x26;     check_enc[3] = 0x46;     for(i=0;i<4;i++){         uint8_t t = (uint8_t)(flagLong[0]>>(8*i));         // printf("%x\t",t);         if(check_enc[i]!=flagLong[check_index[i]]){             success = false;         }     }      char check_enc_last[9] = "61ba69e3";     // snprintf(check_enc_last,9,"%x",flagLong[1]);//3e96ab16     reverse(check_enc_last,0,7);     uint32_t enc_hex = htoi(check_enc_last);      // printf("%x",enc_hex);     if(flagLong[1] == enc_hex){         success = true;     }     if(!success){         printf("You Lost!\n");     }else{         printf("You Win!\n");     }       return 0; }

解题代码:

#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdbool.h>  void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;     for (i=0; i < num_rounds; i++) {         v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);         sum += delta;         v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);     }     v[0]=v0; v[1]=v1; }  void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {     unsigned int i;     uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;     for (i=0; i < num_rounds; i++) {         v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);         sum -= delta;         v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);     }     v[0]=v0; v[1]=v1; } int main() {     uint32_t k[4]={2,2,3,4};     // v为要加密的数据是两个32位无符号整数     // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位      //exchange scale     uint32_t flagLong[2];     flagLong[0] = 0x26a2468c; //enc  26a2468c 3e96ab16     flagLong[1] = 0x3e96ab16;     decipher(32,flagLong,k);     printf("flag{%X-%.08X}\n",flagLong[0],flagLong[1]);      return 0; }

xxTea题目:

#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdbool.h>  #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  void btea(uint32_t *v, int n, uint32_t const key[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;         sum -= DELTA;         } while (--rounds);     } }   int getStr(char *buffer,int maxLen){     char c;  // 读取到的一个字符     int len = 0;  // 当前输入的字符串的长度     // 一次读取一个字符,保存到buffer     // 直到遇到换行符(\n),或者长度超过maxLen时,停止读取     while( (c=getchar()) != '\n' ){         buffer[len++]=c;  // 将读取到的字符保存到buffer         if(len>=maxLen){             break;         }     }     buffer[len]='\0';  // 读取结束,在末尾手动添加字符串结束标志     fflush(stdin);  // 刷新输入缓冲区     return len; }  /*将大写字母转换成小写字母*/   int tolower(int c)   {       if (c >= 'A' && c <= 'Z')       {           return c + 'a' - 'A';       }       else       {           return c;       }   }   //将十六进制的字符串转换成整数   int htoi(char s[])   {       int i = 0;       int n = 0;       if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))       {           i = 2;       }       else       {           i = 0;       }       for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i)       {           if (tolower(s[i]) > '9')           {               n = 16 * n + (10 + tolower(s[i]) - 'a');           }           else           {               n = 16 * n + (tolower(s[i]) - '0');           }       }       return n;   }   void reverse(char *s, int start, int end) {      char t;      while(end>start){         t=s[start];          s[start]=s[end];          s[end]=t;         start++;          end--;      }   }  int main() {     uint32_t v[2]={1,2},k[4]={2,2,3,4};     // v为要加密的数据是两个32位无符号整数     // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位     int flagLen = 0;     bool success = false;     char flag[33];     memset(flag, 0, sizeof(flag));//清空字符串     setbuf(stdin,0);     setbuf(stdout,0);     setbuf(stderr,0);      printf("Please input you flag:");     flagLen = getStr(flag,32);      //check formant     uint8_t vv[5] = {0};     strncpy(vv,flag,4);     uint8_t five = 123;     uint8_t last = 125;     uint8_t *v1,*v2;     if(((uint8_t)flag[5] - five)>0){         printf("five error!");         return -1;     }      if(((uint8_t)flag[flagLen-1] + last) == 250){         ;     }else{         printf("last error!");         return -1;     }      if(strcmp(vv,"flag")){         printf("header error!");         return -1;     }     int mallocSize = flagLen - 6;     char *tokstr = (char *)malloc(sizeof(char)*mallocSize+1);     memset(tokstr, 0, sizeof(tokstr));//清空字符串     strncpy(tokstr,flag+5,mallocSize);      v1 = strtok(tokstr,"-");      v2 = strtok(NULL,"-");      //exchange scale     uint32_t flagLong[2];     flagLong[0] = (uint32_t)htoi((char *)v1);     flagLong[1] = (uint32_t)htoi((char *)v2);     // printf("%d",sizeof(int));  4 byte == 32 bit      // printf("加密前原始数据:%x %x\n",flagLong[0],flagLong[1]);     btea(flagLong,2, k);     // printf("加密后的数据:%x %x\n",flagLong[0],flagLong[1]);     // check flag     uint8_t check_enc[4];     uint8_t check_index[4] = {3,1,0,2};     uint8_t i=0;     check_enc[0] = 0x57;     check_enc[1] = 0x8b;     check_enc[2] = 0x36;     check_enc[3] = 0x9b;     for(i=0;i<4;i++){         uint8_t t = (uint8_t)(flagLong[0]>>(8*i));         // printf("%x\t",t);         if(check_enc[i]!=flagLong[check_index[i]]){             success = false;         }     }      char check_enc_last[9] = "6b45a63b";     // snprintf(check_enc_last,9,"%x",flagLong[1]);//b36a54b6     reverse(check_enc_last,0,7);     uint32_t enc_hex = htoi(check_enc_last);      // printf("%x",enc_hex);     if(flagLong[1] == enc_hex){         success = true;     }     if(!success){         printf("You Lost!\n");     }else{         printf("You Win!\n");     }       return 0; }

解题代码:

#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  void btea(uint32_t *v, int n, uint32_t const key[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;         sum -= DELTA;         } while (--rounds);     } }  int main() {     uint32_t k[4]={2,2,3,4};     // v为要加密的数据是两个32位无符号整数     // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位     //exchange scale     uint32_t flagLong[2];     flagLong[0] = 0x368b9b57;     flagLong[1] = 0xb36a54b6;     btea(flagLong,-2,k);     printf("flag{%X-%.08X}\n",flagLong[0],flagLong[1]);      return 0; }

完。