re | 逆向算法笔记

凯撒算法

加密

for(i=0; i<strlen(passwd); i++)
{
    if(passwd[i] >= 'A' && passwd[i] <= 'Z')
    {
        passwd[i] = ((passwd[i]-'A')+move)%26+'A';
    }
    else if(passwd[i] >= 'a' && passwd[i] <= 'z')
    {
        passwd[i] = ((passwd[i]-'a')+move)%26+'a';
    }
}

解密

for(i=0; i<strlen(passwd); i++)
{
    if(passwd[i] >= 'A' && passwd[i] <= 'Z')
    {
        passwd[i] = ((passwd[i]-'A')+26-move)%26+'A';
    }
    else if(passwd[i] >= 'a' && passwd[i] <= 'z')
    {
        passwd[i] = ((passwd[i]-'a')+26-move)%26+'a';
    }
}

SM4算法

加密

  • 生成s盒

    • 特征是传入128位密钥(v2)

  • 19行异或的数也是sm4的一个特征值

  • 明文加密

    • input划分为4个4字节的值,赋给v5,v5数组按照往后递推的方式,由前4个单元生成后1个单元的值,最后逐个字节取v5[32]到v5[35]的值赋给out

  • sub_411700长这样,第一个v5单元的值和sub_41170函数异或,函数的参数为v5后三个单元和key的异或,最后计算的值再赋给第5个v5单元

解密

import sm4
key = sm4.SM4Key(b"where_are_u_now?")
print key.decrypt(sm4_encoded)

查表算法

加密

a="?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z"
index='PQHRSIDTUJVWKEBXYLZ[MF\]N^_OGCA'
b=[0]*31
for i in range(31):
    b[i]=a[ord(index[i])]

解密

b="?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z"
index='PQHRSIDTUJVWKEBXYLZ[MF\]N^_OGCA'
a=[0]*31
for i in range(31):
    a[ord(index[i])]=b[i]

二叉树算法

加密

typedef struct Node{
	DataType Data;
	struct Node *lchild, *rchild;
}BinTNode, *BiTree;

void Create_BinTree(BiTree *T)
{
	char ch;
	
	scanf("%c",&ch);
	if(ch=='#')
	{
		*T==NULL;
	//	return; 
	} 
	else
	{
		*T=(BinTNode*)malloc(sizeof(BinTNode)); 
		(*T)->Data=ch;
		printf("\n建立左子树\n");
		(*T)->lchild=NULL; 
		(*T)->rchild=NULL;
		Create_BinTree(  &((*T)->lchild ) );//建立左子树 
		printf("\n建立右子树\n");
		Create_BinTree(  &((*T)->rchild ) );//建立右子树 
	}
	return ;
}


void PostOrder_Traverase(BiTree T)//后序遍历 
{
	if(T==NULL)
	return ;
	else
	{
		PostOrder_Traverase(T->lchild);
		PostOrder_Traverase(T->rchild);	
		printf(" %c " , T->Data);
	}
} 

解密

# 二叉树的遍历本质上是一个位置映射,当做一个黑盒处理
# 输入'ABCDEFGHIJKLMNOPQRSTUVWXYZ',程序输出index字符串
# 利用index的位置映射关系来恢复待解密的字符串a

a="?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z"
index='PQHRSIDTUJVWKEBXYLZ[MF\]N^_OGCA'
b=[0]*31
for i in range(31):
    b[ord(index[i])-ord('A')]=a[i]

已知中序和后序,求先序

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char post[] = "20f0Th{2tsIS_icArE}e7__w"; //后序遍历结果
char mid[] = "2f0t02T{hcsiI_SwA__r7Ee}"; //中序遍历结果

void f(int root,int start,int end)
{
    if(start > end)
        return ;
    int i = start;
    while(i < end && mid[i] != post[root])
        i++;   //定位根在中序的位置
    printf("%c",mid[i]);
    f(root - 1-(end - i),start,i - 1);  //递归处理左子树
    f(root-1,i + 1,end);  //递归处理右子树
}

int main()
{

    f(24,0,24);
    return 0;
}

满二叉树已知任一序,可以求任一序

循环左移/右移算法

正运算

  for ( i = 0; i < strlen(input); ++i )
  {
    if ( (i & 1) != 0 )                         // 奇数循环右移
      v1 = (input[i] >> 2) | (input[i] << 6);
    else                                        // 偶数循环左移
      v1 = (4 * input[i]) | (input[i] >> 6);
    input[i] = v1;
  }

逆运算

for i in range(0,len(result)):
    t = result[i]
    if i&1==0:   //偶数循环右移
        input[i]=(t&0x3)<<6|(t&0xfc)>>2   #低2位左移6位,高6位右移2位  相当于循环右移2位
    else:	//奇数循环左移
        input[i]=(t&0x3f)<<2|(t&0xc0)>>6  #低6位左移2位,高2位右移6位  相当于循环左移2位

base64

加密

  • 识别

  • 脚本

    import base64
    str='admin'
    bs64=base64.b64encode(str.encode('utf-8'))
    

解密

  • 识别

    void *__fastcall RxEncode(const char *input, int len)
    {
      void *result; // rax
      int sz; // [rsp+18h] [rbp-38h]
      signed int paddingSz; // [rsp+1Ch] [rbp-34h]
      int idx; // [rsp+20h] [rbp-30h]
      signed int v6; // [rsp+24h] [rbp-2Ch]
      int v7; // [rsp+28h] [rbp-28h]
      int v8; // [rsp+28h] [rbp-28h]
      signed int i; // [rsp+2Ch] [rbp-24h]
      _BYTE *v10; // [rsp+30h] [rbp-20h]
      void *s; // [rsp+38h] [rbp-18h]
    
      sz = 3 * (len / 4);
      paddingSz = 0;
      idx = 0;
      if ( input[len - 1] == '=' )
        paddingSz = 1;
      if ( input[len - 2] == '=' )
        ++paddingSz;
      if ( input[len - 3] == '=' )
        ++paddingSz;
      if ( paddingSz == 3 )
      {
        sz += 2;
      }
      else if ( paddingSz <= 3 )
      {
        if ( paddingSz == 2 )
        {
          sz += 3;
        }
        else if ( paddingSz <= 2 )
        {
          if ( paddingSz )
          {
            if ( paddingSz == 1 )
              sz += 4;
          }
          else
          {
            sz += 4;
          }
        }
      }
      s = malloc(sz);
      if ( s )
      {
        memset(s, 0, sz);
        v10 = s;
        while ( idx < len - paddingSz )
        {
          v6 = 0;
          v7 = 0;
          while ( v6 <= 3 && idx < len - paddingSz )
          {
            v7 = (v7 << 6) | (char)find_pos(input[idx]);
            ++v6;
            ++idx;
          }
          v8 = v7 << 6 * (4 - v6);
          for ( i = 0; i <= 2 && i != v6; ++i )
            *v10++ = v8 >> 8 * (2 - i);
        }
        *v10 = 0;
        result = s;
      }
      else
      {
        puts("No enough memory.");
        result = 0LL;
      }
      return result;
    }
    
  • 脚本

    import base64
    debs64=base64.b64decode(bs64)
    

换表的base64解密脚本

import base64
import string

str1 = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q"

string1 = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))

base58

  strcpy(v23, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
  v21 = 138 * strlen(v19) / 0x64;
  v14 = v21 + 1;
  v1 = 0;
  v22 = (_BYTE *)MEMORY[0x8114](v21 + 1);
  v2 = v22;
  sub_402C08(v22, 0, v14);
  v3 = v19;
  v20 = (int)(v19 + 1);
  if ( strlen(v19) )
  {
    v4 = &v2[v21];
    v18 = v4;
    while ( 1 )
    {
      v20 = ((char)*v4 << 8) + v3[v1];
      v5 = v20 / 58;
      *v4 = v20 % 58;
      if ( v5 )
      {
        do
        {
          v6 = (char)*--v4;
          v7 = (v6 << 8) + v5;
          v20 = v7 / 58;
          *v4 = v7 % 58;
          v5 = v20;
        }
        while ( v20 );
        v4 = v18;
      }
      if ( ++v1 >= strlen(v19) )
        break;
      v3 = v19;
    }
    v2 = v22;
  }
  v8 = 0;
  if ( !*v2 )
  {
    do
      ++v8;
    while ( !v2[v8] );
  }
  v9 = v21;
  if ( v8 <= v21 )
  {
    v10 = v2 - (_BYTE *)v24;
    do
    {
      v11 = (char *)v24 + v8++;
      *v11 = v23[(char)v11[v10]];
    }
    while ( v8 <= v9 );
  }
  if ( !MEMORY[0x7C1A](v24, "56fkoP8KhwCf3v7CEz") )

tea系列算法

tea

  • TEA加密解密是以原文以8字节(64位bit)为一组,密钥16字节(128位bit)为一组,该算法加密轮次可变,作者建议为32轮,因为被加密的明文为64位,所以最终加密的结果也是64位

  • 实现

    #include <stdio.h>
    #include <stdint.h>
     
    //加密函数
    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;
    }
    
    //解密函数
    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;
    }
    

xtea

  • XTEA是TEA的升级版,增加了更多的密钥表,移位和异或操作

  • 实现

    #include <stdio.h>
    #include <stdint.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 main()
    {
        uint32_t v[2]={1,2};
        uint32_t const k[4]={2,2,3,4};
        unsigned int r=32;//num_rounds建议取值为32
        // v为要加密的数据是两个32位无符号整数
        // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
        printf("加密前原始数据:%u %u\n",v[0],v[1]);
        encipher(r, v, k);
        printf("加密后的数据:%u %u\n",v[0],v[1]);
        decipher(r, v, k);
        printf("解密后的数据:%u %u\n",v[0],v[1]);
        return 0;
    }
    

xxtea

  • 特点:原字符串长度可以不是4的倍数了

  • 实现

    #include <stdio.h>
    #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);
        }
    }
     
     
    int main()
    {
        uint32_t v[2]= {1,2};
        uint32_t const k[4]= {2,2,3,4};
        int n= 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
        // v为要加密的数据是两个32位无符号整数
        // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
        printf("加密前原始数据:%u %u\n",v[0],v[1]);
        btea(v, n, k);
        printf("加密后的数据:%u %u\n",v[0],v[1]);
        btea(v, -n, k);
        printf("解密后的数据:%u %u\n",v[0],v[1]);
        return 0;
    }
    
    
  • (链接)vs中导入头文件编译,可直接使用decode函数

RC4算法

  • RC4加密原理很简单,只需要一个KeyStream与明文进行异或即可,密钥流的长度和明文的长度是对应的。RC4算法的的主要代码还是在于如何生成秘钥流
  • 密钥流的生成由两部分组成:
    • KSA(the Key-Scheduling Algorithm)
    • PRGA(the Pseudo-Random Generation Algorithm)
  • 实现
#include<stdio.h>
#include<string.h>
 
#define SBOX_LEN 256
 
#define rc4_encrypt rc4_crypt
#define rc4_decrypt rc4_crypt
 
static inline void swap_uchar(unsigned char *puc_x, unsigned char *puc_y)
{
    *puc_x = *puc_x ^ *puc_y;
    *puc_y = *puc_x ^ *puc_y;
    *puc_x = *puc_x ^ *puc_y;
}
 
void hexdump(unsigned char *puc_data, int length)
{
    int i = 0;
 
    for (i = 0; i < length; i++) {
        printf("%02X", puc_data[i]);
        if (i && (i + 1) % 16 == 0) {
            putchar('\n');
        }
    }
    printf("\n");
}
 
/**
 * 利用Key生成S盒,伪随机数生成器
 * the Key-Scheduling Algorithm
 */
static void rc4_ksa(unsigned char *puc_sbox, unsigned char *puc_key, int key_length)
{
    int i = 0;
    int j = 0;
    char tmp[SBOX_LEN] = {0};
 
    for (i = 0; i < SBOX_LEN; i++) {
        puc_sbox[i] = i;
        tmp[i] = puc_key[i % key_length];
    }
 
    for (i = 0; i < SBOX_LEN; i++) {
        j = (j + puc_sbox[i] + tmp[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]); //交换puc_sbox[i]和puc_sbox[j]
    }
}
 
/**
 * 利用S盒生成密钥流
 * The pseudo-random generation algorithm(PRGA)
 */
static void rc4_prga(unsigned char *puc_sbox, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    int i = 0;
    int j = 0;
    int t = 0;
    unsigned long k = 0;
 
    for (k = 0; k < ul_data_length; k++) {
        i = (i + 1) % SBOX_LEN;
        j = (j + puc_sbox[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]);
        t = (puc_sbox[i] + puc_sbox[j]) % SBOX_LEN;
        /* 为了更清晰理解rc4算法流程,此处保存keystream,不直接进行XOR运算 */
        puc_key_stream[k] = puc_sbox[t];
    }
}
 
/* 加解密 */
void rc4_crypt(unsigned char *puc_data, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    unsigned long i = 0;
 
    /* 把PRGA算法放在加解密函数中可以不需要保存keystream */
    for (i = 0; i < ul_data_length; i++) {
        puc_data[i] ^= puc_key_stream[i];
    }
}
 
int main(int argc, char *argv[])
{
    unsigned char sbox[SBOX_LEN] = {0};
    char key[SBOX_LEN] = {"abcdefghijklmnopqrstuvwxyz"}; //秘钥内容随便定义
    char data[512] = "lsRJ@.0 lvfvr#9527";
    unsigned char puc_keystream[512] = {0};
    unsigned long ul_data_length = strlen(data);
 
    printf("key=%s, length=%d\n\n", key, strlen(key));
    printf("Raw data string:%s\n", data);
    printf("Raw data hex:\n");
    hexdump(data, ul_data_length);
 
    /* 生成S-box */
    rc4_ksa(sbox, (unsigned char *)key, strlen(key));
 
    /* 生成keystream并保存,S-box也会被更改 */
    rc4_prga(sbox, puc_keystream, ul_data_length);
 
    printf("S-box final status:\n");
    hexdump(sbox, sizeof(sbox));
 
    printf("key stream:\n");
    hexdump(puc_keystream, ul_data_length);
 
    /* 加密 */
    rc4_encrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("cipher hexdump:\n");
    hexdump(data, ul_data_length);
 
    /* 解密 */
    rc4_decrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("decypt data:%s\n", data);
 
    return 0;
}
  • 脚本
from Crypto.Cipher import ARC4
rc4 = ARC4.new(key)
print rc4.decrypt(encoded)

CRC算法

/*
**初始化crc表,生成32位大小的crc表
**也可以直接定义出crc表,直接查表,
**但总共有256个,看着眼花,用生成的比较方便,
**对0-255进行模2除法生成crc表.
*/
static void init_crc_table(void)
{
	unsigned int c;
	unsigned int i, j;
	
	for (i = 0; i < 256; i++) {
		c = (unsigned int)i;
		for (j = 0; j < 8; j++) {
			if (c & 1)
				c = 0xedb88320L ^ (c >> 1);
			else
				c = c >> 1;
		}
		crc_table[i] = c;
	}
}
 
/*计算buffer的crc校验码*/
static unsigned int crc32(unsigned int crc,unsigned char *buffer, unsigned int size)
{
	unsigned int i;
	for (i = 0; i < size; i++) {
		crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
	}
	return crc ;
}

MD5算法

特征值

void MD5Init (MD5_CTX *context)
{
   /*将当前的有效信息的长度设成0,这个很简单,还没有有效信息,长度当然是0了*/
  context->count[0] = context->count[1] = 0;
   /* Load magic initialization constants.*/
  /*初始化变量,算法要求这样 */
  context->state[0] = 0x67452301;
  context->state[1] = 0xefcdab89;
  context->state[2] = 0x98badcfe;
  context->state[3] = 0x10325476;
}

RSA算法

加密

  • 选取两个大素数p和q,为了获得最高安全性,设两数长度一样

  • 计算n=p*q,n称为模

  • 选取加密密钥e,其与φ(n)互素。如果选择的e值合适,RSA加解密的速度会加快。e的常用值为3、17、和65537(2^16+1)

  • 公钥为e和n,加密消息m时,将其看成一个大整数,并把它分成比n小的数据分组

    c[i] = m[i]^e mod n
    

解密

  • 计算欧拉函数:

    φ(n)=(p-1)(q-1)
    
  • 使用扩展欧几里德算法求出e模φ(n)的逆元d

    e*d mod φ(n) = 1
    
  • 密钥为d和n,解密密文c时,取每个加密后的分组c[i]

    m[i] = c[i]^d mod n
    

还原

  • 分解公钥得到e和n 链接
  • 分解n得到p和q 链接
  • 脚本
import gmpy2 
import rsa 
 
e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phin = (q-1)*(p-1)

d = gmpy2.invert(e, phin)

key = rsa.PrivateKey(n, e, int(d), p, q)

with open("G:\\output\\flag.txt", "rb+") as f:
    f = f.read()
    print(rsa.decrypt(f, key))

AES算法

原理

特征

  • 密文的长度必须是0x10字节的倍数

  • 秘钥的长度是 0x10 或0x18或0x20字节

  • T1-T4 静态数组数据用于加密数据,T5-T8 静态数组数据用于解密数据,其他静态数组用于初始化

模式

  • ECB

  • CBC

代码实现

#include <stdio.h>
#include <windows.h>

/*s盒矩阵:The AES Substitution Table*/// 256 位的密匙256 位支持长度为32 个字符
static const unsigned char sbox[256] = {
	0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,
	0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
	0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,
	0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
	0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,
	0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
	0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,
	0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
	0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,
	0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
	0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,
	0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
	0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,
	0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
	0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,
	0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
	0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,
	0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
	0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,
	0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
	0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,
	0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
	0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,
	0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
	0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,
	0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
	0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,
	0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
	0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,
	0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
	0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,
	0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
};
//逆向S 盒矩阵
static const unsigned char contrary_sbox[256] = {
	0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
	0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
	0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
	0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
	0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
	0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
	0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
	0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
	0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
	0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
	0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
	0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
	0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
	0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
	0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
	0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
	0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
	0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
	0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
	0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
	0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
	0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
	0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
	0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
	0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
	0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
	0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
	0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
	0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
	0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
	0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
	0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,
};
/*轮常量表 The key schedule rcon table*/
static const unsigned char Rcon[10] = {
	0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36 };

//辅助函数
/*有限域*2乘法 The x2time() function */
static unsigned char x2time(unsigned char x)
{
	if (x & 0x80)
	{
		return (((x << 1) ^ 0x1B) & 0xFF);
	}
	return x << 1;
}
/*有限域*3乘法 The x2time() function */
static unsigned char x3time(unsigned char x)
{
	return (x2time(x) ^ x);
}
/*有限域*4乘法 The x4time() function */
static unsigned char x4time(unsigned char x)
{
	return (x2time(x2time(x)));
}
/*有限域*8乘法 The x8time() function */
static unsigned char x8time(unsigned char x)
{
	return (x2time(x2time(x2time(x))));
}
/*有限域9乘法 The x9time() function */
static unsigned char x9time(unsigned char x)	//9:1001
{
	return (x8time(x) ^ x);
}
/*有限域*B乘法 The xBtime() function */
static unsigned char xBtime(unsigned char x)	//B:1011
{
	return (x8time(x) ^ x2time(x) ^ x);
}
/*有限域*D乘法 The xDtime() function */
static unsigned char xDtime(unsigned char x)	//D:1101
{
	return (x8time(x) ^ x4time(x) ^ x);
}
/*有限域*E乘法 The xEtime() function */
static unsigned char xEtime(unsigned char x)	//E:1110
{
	return (x8time(x) ^ x4time(x) ^ x2time(x));
}
/*第三类操作:列混合操作 MixColumns: Process the entire block*/
static void MixColumns(unsigned char *col)//列混合
{
	unsigned char tmp[4], xt[4];
	int i;
	for (i = 0; i<4; i++, col += 4)  //col代表一列的基地址,col+4:下一列的基地址
	{
		tmp[0] = x2time(col[0]) ^ x3time(col[1]) ^ col[2] ^ col[3];	//2 3 1 1
		tmp[1] = col[0] ^ x2time(col[1]) ^ x3time(col[2]) ^ col[3];	//1 2 3 1
		tmp[2] = col[0] ^ col[1] ^ x2time(col[2]) ^ x3time(col[3]);	//1 1 2 3
		tmp[3] = x3time(col[0]) ^ col[1] ^ col[2] ^ x2time(col[3]);	//3 1 1 2
//修改后的值 直接在原矩阵上修改
		col[0] = tmp[0];
		col[1] = tmp[1];
		col[2] = tmp[2];
		col[3] = tmp[3];
	}
}
//逆向列混淆
static void Contrary_MixColumns(unsigned char *col)
{
	unsigned char tmp[4];
	unsigned char xt2[4];//colx2
	unsigned char xt4[4];//colx4
	unsigned char xt8[4];//colx8
	int x;
	for (x = 0; x<4; x++, col += 4)
	{
		tmp[0] = xEtime(col[0]) ^ xBtime(col[1]) ^ xDtime(col[2]) ^ x9time(col[3]);
		tmp[1] = x9time(col[0]) ^ xEtime(col[1]) ^ xBtime(col[2]) ^ xDtime(col[3]);
		tmp[2] = xDtime(col[0]) ^ x9time(col[1]) ^ xEtime(col[2]) ^ xBtime(col[3]);
		tmp[3] = xBtime(col[0]) ^ xDtime(col[1]) ^ x9time(col[2]) ^ xEtime(col[3]);
		col[0] = tmp[0];
		col[1] = tmp[1];
		col[2] = tmp[2];
		col[3] = tmp[3];
	}
}
/*第二类操作:行移位:行左循环移位 ShiftRows:Shifts the entire block*/
static void ShiftRows(unsigned char *col)//正向行移位
{
	unsigned char t;
	t = col[1]; col[1] = col[5]; col[5] = col[9]; col[9] = col[13]; col[13] = t;
	t = col[2]; col[2] = col[10]; col[10] = t;
	t = col[6]; col[6] = col[14]; col[14] = t;
	t = col[15]; col[15] = col[11]; col[11] = col[7]; col[7] = col[3]; col[3] = t;
}
//逆向行移位
static void Contrary_ShiftRows(unsigned char *col)
{
	unsigned char t;
	t = col[13]; col[13] = col[9]; col[9] = col[5]; col[5] = col[1]; col[1] = t;
	t = col[2]; col[2] = col[10]; col[10] = t;
	t = col[6]; col[6] = col[14]; col[14] = t;
	t = col[3]; col[3] = col[7]; col[7] = col[11]; col[11] = col[15]; col[15] = t;
}
/*第一类操作:s盒字节代换替换 SubBytes*/
static void SubBytes(unsigned char *col)//字节代换
{
	int x;
	for (x = 0; x<16; x++)
	{
		col[x] = sbox[col[x]];
	}
}
//逆向字节代换
static void Contrary_SubBytes(unsigned char *col)
{
	int x;
	for (x = 0; x<16; x++)
	{
		col[x] = contrary_sbox[col[x]];
	}
}
/*第四类操作:轮密钥加 AddRoundKey*/
static void AddRoundKey(unsigned char *col, unsigned char *expansionkey, int round)//密匙加
{
	//扩展密钥:44*32bit =11*4* 4*8 =  16字节*11轮,每轮用16字节密钥
	//第0轮,只进行一次轮密钥加
	//第1-10轮,轮密钥加
	int x;
	for (x = 0; x<16; x++)	//每1轮操作:4*32bit密钥 = 16个字节密钥
	{
		col[x] ^= expansionkey[(round << 4) + x];
	}
}
/* AES加密总函数 10轮4类操作 Encrypt a single block with Nr Rounds(10,12,14)*/
void AesEncrypt(unsigned char *blk, unsigned char *expansionkey, int Nr)//加密一个区块
{
	//输入blk原文,直接在上面修改,输出blk密文
	//输入skey:
	//输入Nr = 10轮
	int round;
	//第1轮之前:轮密钥加
	AddRoundKey(blk, expansionkey, 0);
	//第1-9轮:4类操作:字节代换、行移位、列混合、轮密钥加
	for (round = 1; round <= (Nr - 1); round++)
	{
		SubBytes(blk);		//输入16字节数组,直接在原数组上修改
		ShiftRows(blk);		//输入16字节数组,直接在原数组上修改
		MixColumns(blk);	//输入16字节数组,直接在原数组上修改
		AddRoundKey(blk, expansionkey, round);
	}
	//第10轮:不进行列混合
	SubBytes(blk);
	ShiftRows(blk);
	AddRoundKey(blk, expansionkey, Nr);
}
//AES 解密总函数
void Contrary_AesEncrypt(unsigned char *blk, unsigned char *expansionkey, int Nr)
{
	int x;
	/* unsigned char *contrary_key=key;
	for(x=0;x<11;x++,key+=16)
	Contrary_MixColumns(key);*/
	AddRoundKey(blk, expansionkey, Nr);
	Contrary_ShiftRows(blk);
	Contrary_SubBytes(blk);
	for (x = (Nr - 1); x >= 1; x--)
	{
		AddRoundKey(blk, expansionkey, x);
		Contrary_MixColumns(blk);
		Contrary_ShiftRows(blk);
		Contrary_SubBytes(blk);
	}
	AddRoundKey(blk, expansionkey, 0);
}
/*//密钥编排,16字节--->44列32bit密钥生成--> 11组16字节:分别用于11轮 轮密钥加运算
Schedule a secret key for use.
*outkey[] must be 16*15 bytes in size
*Nk==number of 32 bit words in the key,e.g.,4,6,8
*Nr==number of rounds,e.g.,10,12,14
*/
void ScheduleKey(unsigned char *inkey, unsigned char *outkey, int Nk, int Nr)//安排一个保密密钥使用
{
	//inkey:初始16字节密钥key
	//outkey:11组*16字节扩展密钥expansionkey
	//Nk:4列
	//Nr:10轮round
	unsigned char temp[4], t;
	int x, i;
	/*copy the key*/
	//第0组:[0-3]直接拷贝
	for (i = 0; i<(4 * Nk); i++)
	{
		outkey[i] = inkey[i];
	}
	//第1-10组:[4-43]
	i = Nk;
	while (i<(4 * (Nr + 1))) //i=4~43 WORD 32bit的首字节地址,每一个4字节
	{//1次循环生成1个字节扩展密钥,4次循环生成一个WORD
	 //temp:4字节数组:代表一个WORD密钥
	 /*temp=w[i-1]*/
	 //i不是4的倍数的时候
	 //每个temp = 每个outkey32bit = 4字节
		for (x = 0; x<4; x++)
			temp[x] = outkey[(4 * (i - 1)) + x];	//i:32bit的首字节地址
													//i是4的倍数的时候
		if (i%Nk == 0)
		{
			/*字循环:循环左移1字节 RotWord()*/
			t = temp[0]; temp[0] = temp[1]; temp[1] = temp[2]; temp[2] = temp[3]; temp[3] = t;
			/*字节代换:SubWord()*/
			for (x = 0; x<4; x++)
			{
				temp[x] = sbox[temp[x]];
			}
			/*轮常量异或:Rcon[j]*/
			temp[0] ^= Rcon[(i / Nk) - 1];
		}
		/*w[i] = w[i-4]^w[i-1]*/
		for (x = 0; x<4; x++)
		{
			outkey[(4 * i) + x] = outkey[(4 * (i - Nk)) + x] ^ temp[x];
		}
		++i;
	}
}
int main(void) {
	/*
	pt:原文16字节-->密文
	key:原密钥16字节
	skey:密钥扩展44long
	sbox:s盒
	*/

	unsigned char pt[17], key[17];
	unsigned char expansionkey[15 * 16];
	int i;
	int j;
	printf("输入需要加密字符串: \n");//输入无格式的字符串字符个数不得少于六个!
	scanf("%s", pt);
	printf("输入加密密钥: \n");//输入加密钥匙密匙个数不得低于六个!
	scanf("%s", key);

	/*加密*/
	ScheduleKey(key, expansionkey, 4, 10);	//1、密钥扩展生成
	AesEncrypt(pt, expansionkey, 10);		//2、AES 加密
	printf("加密后的数据:  ");	//输出密码文件

	for (i = 0; i < 16; i++)
		printf("%02x ", pt[i]);
	printf("\n");

	/*解密*/
	Contrary_AesEncrypt(pt, expansionkey, 10);//AES 解密
	printf("解密后的数据: ");//将解密文件输出
	for (i = 0; i < 16; i++)
		printf("%c ", pt[i]);

	system("pause");
	return 0;
}

脚本还原

  • ECB
from Crypto.Cipher import AES

password = b'1234567812345678' #秘钥,b就是表示为bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_ECB) #创建一个aes对象
# AES.MODE_ECB 表示模式是ECB模式
en_text = aes.encrypt(text) #加密明文
print("密文:",en_text) #加密明文,bytes类型
den_text = aes.decrypt(en_text) # 解密密文
print("明文:",den_text)
  • CBC
from Crypto.Cipher import AES
password = b'1234567812345678' #秘钥,b就是表示为bytes类型
iv = b'1234567812345678' # iv偏移量,bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_CBC,iv) #创建一个aes对象
# AES.MODE_CBC 表示模式是CBC模式
en_text = aes.encrypt(text) 
print("密文:",en_text) #加密明文,bytes类型
aes = AES.new(password,AES.MODE_CBC,iv) #CBC模式下解密需要重新创建一个aes对象
den_text = aes.decrypt(en_text)
print("明文:",den_text)

DES算法

原理

特征

  • 密文的长度必须是0x08字节的倍数

  • 秘钥的长度必须是 0x08字节

代码实现

/*************************************************************************

    > File Name: DES.cpp

    > Author: YB

    > E-mail: 1348756432@qq.com

    > Created Time: 2019年03月01日 星期五

 ************************************************************************/
#include <bits/stdc++.h>
using namespace std;

/**

 *数据初始置换表

 */
int T1[8][8]={58,50,42,34,26,18,10,2,
              60,52,44,36,28,20,12,4,
              62,54,46,38,30,22,14,6,
              64,56,48,40,32,24,16,8,
              57,49,41,33,25,17,9,1,
              59,51,43,35,27,19,11,3,
              61,53,45,37,29,21,13,5,
              63,55,47,39,31,23,15,7};
/**

 *密钥初始置换表

 */
int T2[8][7]={57,49,41,33,25,17,9,
              1,58,50,42,34,26,18,
              10,2,59,51,43,35,27,
              19,11,3,60,52,44,36,
              3,55,47,39,31,23,15,
              7,62,54,46,38,30,22,
              14,6,61,53,45,37,29,
              21,13,5,28,20,12,4};

/**

 *密钥循环左移位数表

 */
int T3[16]={1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};

/**

 *密钥压缩置换表

 */
int T4[8][6]={14,17,11,24,1,5,
              3,28,15,6,21,10,
              23,19,12,4,26,8,
              16,7,27,20,13,2,
              41,52,31,37,47,55,
              30,40,51,45,33,48,
              44,49,39,56,34,53,
              46,42,50,36,29,32};

/**

 *数据扩展表

 */
int T5[8][6]={32,1,2,3,4,5,
              4,5,6,7,8,9,
              8,9,10,11,12,13,
              12,13,14,15,16,17,
              16,17,18,19,20,21,
              20,21,22,23,24,25,
              24,25,26,27,28,29,
              28,29,30,31,32,1};

/**

 *S盒置换表

 */
int S[8][4][16]={{{14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},{0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},{4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},{15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}},
                {{15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},{3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},{ 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},{ 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}},
                {{10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},{13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},{13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},{1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}},
                {{7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},{13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},{10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},{3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}},
                {{2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},{14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},{4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},{11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}},
                {{12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},{10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},{9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},{4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}},
                {{4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},{13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},{1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},{6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}},
                {{13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},{1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},{7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},{2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}}};

/**

 *P盒置换表

 */
int P[4][8]={16,7,20,21,
             29,12,28,17,
             1,15,23,26,
             5,18,31,10,
             2,8,24,14,
             32,27,3,9,
             19,13,30,6,
             22,11,4,25};


/**

 *最终置换表

 */
int T6[8][8]={  40,8,48,16,56,24,64,32,
                  39,7,47,15,55,23,63,31,
                  38,6,46,14,54,22,62,30,
                  37,5,45,13,53,21,61,29,
                  36,4,44,12,52,20,60,28,
                  35,3,43,11,51,19,59,27,
                  34,2,42,10,50,18,58,26,
                  33,1,41,9,49,17,57,25};

/**

 *最终置换函数 64位->64位

 *函数说明:s为完成最后一轮循环得到的64为数据

 *返回值为密文或明文

 */
string final_permutation(string s)
{
    string rs="";
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            rs+=s[T6[i][j]-1];
        }
    }
    return rs;
}

/**

 *P盒置换函数 32位->32位

 *函数说明:s为S盒的输出

 */
string P_box(string s)
{
    string rs="";
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<8;j++)
        {
            rs+=(s[P[i][j]-1]);
        }
    }
    return rs;
}

/**

 *S盒置换函数 48位->32位

 *函数说明:s为48位数据

 *返回值为32位

 */
string S_box(string s)
{
    string rs="";
    string s1;
    int k1,k2;//S盒的行号和列号
    int h=1;//决定使用那个S盒
    for(int i=0;i<=42;i=i+6,h++)
    {
        k1=(s[i]-'0')*2+(s[i+5]-'0')*1;
        k2=(s[i+1]-'0')*8+(s[i+2]-'0')*4+(s[i+3]-'0')*2+(s[i+4]-'0')*1;
        int x=S[h-1][k1][k2];
        s1="";
        int y=8;
        for(int j=1;j<=4;j++)
        {
            if(x<y)
            {
                s1+="0";
                y/=2;
            }else
            {
                s1+="1";
                x=x%y;
                y/=2;
            }
        }
        rs+=s1;
    }
    return rs;
}

/**

 *异或运算函数

 *要求位数相同

 */
string XOR(string s1,string s2)
{
    string rs="";
    for(int i=0;i<s1.length()&&i<s2.length();i++)
    {
        rs+=((s1[i]-'0')^(s2[i]-'0'))+'0';
    }
    return rs;
}

/**

 *数据扩展函数 32->48

 *函数说明:s为数据的右半部分 32位

 *扩展成48位的输出

 */
string plaintext_righthalf_extended_permutation(string s)
{
    string rs="";
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<6;j++)
        {
            rs+=s[T5[i][j]-1];
        }
    }
    return rs;
}

/**

 *密钥压缩置换函数 56位->48位

 *函数说明:s为56为的密钥

 *输出为48位的子密钥

 */
string secret_key_compression_replacement(string s)
{
    string rs="";
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<6;j++)
        {
            rs+=s[T4[i][j]-1];
        }
    }
    return rs;
}

/**

 *密钥循环左移函数 56位->56位

 *函数说明:k为左移位数 s为密钥

 *返回值位数不变

 */
string secret_ket_left_move(int k,string s)//密钥循环左移k位
{
    string s1=s.substr(0,28);
    string s2=s.substr(28,28);
    string rs=s1.substr(k,28-k)+s1.substr(0,k)+s2.substr(k,28-k)+s2.substr(0,k);
    return rs;
}

/**

 *密钥初始置换函数 64位->58位

 *函数说明:s为64位的初始密钥

 *返回值为58位

 */
string secret_key_initial_permutation(string s)
{
    string rs="";
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<7;j++)
        {
            rs+=s[T2[i][j]-1];
        }
    }
    return rs;
}

/**

 *明文初始置换函数 64位->64位

 *函数说明:s为初始明文 64位

 *返回值为6位

 */
string plaintext_initial_permutation(string s)//明文初始置换
{
    string rs="";
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            rs+=s[T1[i][j]-1];
        }
    }
    return rs;
}

/**

 *16进制转2进制函数

 *函数说明:s为16进制字符串

 *返回为2进制字符串

 */
string H(string s)
{
    string s1;
    string rs="";
    for(int i=0;i<s.length();i++)
    {
        int x;
        if(s[i]>='0'&&s[i]<='9')
        {
            x=s[i]-'0';
        }else
        {
            x=s[i]-'A'+10;
        }
        s1="";
        int y=8;
        for(int j=1;j<=4;j++)
        {
            if(x<y)
            {
                y/=2;
                s1+="0";
            }else
            {
                s1+="1";
                x=x%y;
                y=y/2;
            }
        }
        rs+=s1;
    }
    return rs;
}

 /**

 *2进制转16进制函数

 *str为2进制字符串

 *返回值为16进制字符串

 */
string G(string str)
{
    string rs="";
    char temp;
    for(int i=0;i<=str.length()-4;i=i+4)
    {
        int x=(str[i]-'0')*8+(str[i+1]-'0')*4+(str[i+2]-'0')*2+str[i+3]-'0';

        if(x>=10)
        {
            temp=(char)(x-10+'A');
        }else
        {
            temp=(char)(x+'0');
        }
        rs+=temp;
    }
    return rs;
}

/**

 *封装函数f

 *函数说明:接收32位数据和48位的子密钥 产生一个32位的输出

 *str1:32位数据  str2:48位的子密钥

 *返回值32位

 */

string f(string str1,string str2)
{
    string expendR=plaintext_righthalf_extended_permutation(str1);
    cout<<"32位数据扩展为48位结果:"<<expendR<<endl;

    string rs=XOR(expendR,str2);
    cout<<"密钥和扩展数据异或结果:"<<rs<<endl;

    rs=S_box(rs);
    cout<<"S盒替代结果(48->32):"<<rs<<endl;

    rs=P_box(rs);
    cout<<"P盒替代结果(32->32):"<<rs<<endl;

    return rs;
}

/**

 *子密钥生成函数

 *函数说明:s为给定的密钥

 *生成16个子密钥

 */
string Keys[20];

void generateKeys(string s)
{
    s=secret_key_initial_permutation(s);

    for(int i=1;i<=16;i++)
    {
        s=secret_ket_left_move(T3[i-1],s);
        Keys[i]=secret_key_compression_replacement(s);
        cout<<"K"<<i<<":"<<Keys[i]<<endl;
    }
    cout<<endl;
}

/**

 *DES加密函数 64位->64位

 *函数说明:str1为64位的给定明文

 *返回值为64位的密文

 */
 string encrypt(string str1)
 {
     //第一步:明文初始置换 64->64
     str1=plaintext_initial_permutation(str1);
     cout<<"明文初始置换结果(64->64):"<<str1<<endl<<endl;

     //第二步:数据分组
     string left=str1.substr(0,32);
     string right=str1.substr(32,32);
     cout<<"L0:"<<left<<endl;
     cout<<"R0:"<<right<<endl<<endl;

     string newleft;

     //第三步:16轮迭代
     for(int i=1;i<=16;i++)
     {
         cout<<"第"<<i<<"次迭代"<<endl;
         newleft=right;

         right=XOR(left,f(right,Keys[i]));

         left=newleft;

         cout<<"L["<<i<<"]:"<<left<<endl;
         cout<<"R["<<i<<"]:"<<right<<endl<<endl;
     }

     //第四步:合并数据 注意位R16L16
     string rs=right+left;
     cout<<"R16L16:"<<rs<<endl<<endl;

     //结尾置换
     rs=final_permutation(rs);
     cout<<"最终置换结果:"<<rs<<endl<<endl;
     return rs;

 }
 /**

 *解密函数

 *str为密文

 *输出明文

 */
 string decrypt(string str)
 {
     //把密文当作明文进行初始明文置换
     str=plaintext_initial_permutation(str);
     cout<<"密文当作明文初始置换结果(64->64):"<<str<<endl<<endl;

     //分组
     string left=str.substr(0,32);
     string right=str.substr(32,32);
     cout<<"L0:"<<left<<endl;
     cout<<"R0:"<<right<<endl<<endl;

     string newleft;

     //逆序的子密钥使用 16轮迭代
     for(int i=16;i>=1;i--)
     {
          cout<<"第"<<17-i<<"次迭代"<<endl;

         newleft=right;
         right=XOR(left,f(right,Keys[i]));
         left=newleft;

         cout<<"L["<<17-i<<"]:"<<left<<endl;
         cout<<"R["<<17-i<<"]:"<<right<<endl<<endl;
     }

     //合并
     string rs=right+left;
     cout<<"R16L16:"<<rs<<endl<<endl;

     //最后置换
     rs=final_permutation(rs);
     cout<<"最终置换结果:"<<rs<<endl<<endl;

     return rs;
 }
int main()
{
   //明文 16进制
   string str1="0123456789ABCDEF";
   //密钥16进制
   string str2="133457799BBCDFF1";

   string temp=str1;//保存十六进制的明文以便后面验证算法正确性

   //进制转换 16->2
   str1=H(str1);
   str2=H(str2);
   cout<<"二进制明文:"<<str1<<endl;
   cout<<"二进制密文:"<<str2<<endl<<endl;

   cout<<"16个子密钥:"<<endl;
   //生成16个子密钥
   generateKeys(str2);

   //加密
   string rs=encrypt(str1);
   cout<<"密文(二进制):"<<rs<<endl;

   cout<<"密文(16进制):"<<G(rs)<<endl;

   cout<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<endl<<"下面是解密过程数据"<<endl<<endl;

   //解密
   rs=decrypt(rs);

   cout<<"明文(二进制):"<<rs<<endl;

   //进制转换
   rs=G(rs);

   cout<<"明文(16进制):"<<rs<<endl;

   if(temp==rs)
    cout<<"解密得到的明文和初始明文匹配成功,算法正确"<<endl;
   else
    cout<<"解密得到的明文和初始明文匹配不成功,算法错误"<<endl;

   return 0;
}

脚本还原

import base64
from Crypto.Cipher import DES

encryptData = "xZWDZaKEhWNMCbiGYPBIlY3+arozO9zonwrYLiVL4njSez2RYM2WwsGnsnjCDnHs7N43aFvNE54noSadP9F8eEpvTs5QPG+KL0TDE/40nbU="
e = base64.b64decode(encryptData)
# 在C#中,字符串默认是Unicode字符串,所以转成字节数组,在每个字符字节后都要加一个"\x00"
keyiv = b"t\x00e\x00s\x00t\x00"

d = DES.new(keyiv, DES.MODE_CBC, keyiv)
print(d.decrypt(e).decode("utf-16"))
posted @ 2023-06-27 12:02  z5onk0  阅读(57)  评论(0编辑  收藏  举报