文档章节

适合单片机的AES加解密源码

h
 houj
发布于 2014/12/06 11:45
字数 2176
阅读 289
收藏 1

适合单片机的AES加解密源码


Aes.h

/*适合单片机的AES加解密
 * Aes.h
 *
 *  Created on: 2014年12月6日
 *      Author: houj
 */


//代表以字为单位的块长
#define AES_NB (4)
#define AES_NB_MASK (AES_NB-1)


#ifndef FALSE
#define FALSE (0)
#endif

#ifndef TRUE
#define TRUE (1)
#endif
typedef unsigned char u8;
typedef signed long u32;

typedef struct {
   int nc; //轮数  10 12 14
   int len; //密钥长度 16 24 32
   u8 keyw[AES_NB * (14 + 1)][4];   //为密钥调度表
} AesKey;


/*********************************************************************************************
 * 名称: aes_initKey
 * 功能: 初始化AES密钥
 * 参数: AesKey* pkey: 打初始化的密钥
 * 参数: u8 *key: 密钥原始字节
 * 参数: int keysize: 密钥长度
 * 返回: boolean: 是否成功
 ********************************************************************************************/
boolean aes_initKey(AesKey* pkey, u8 *key, int keysize);


/*********************************************************************************************
 * 名称: aes_encrypt
 * 功能: AES加密
 * 参数: const AesKey* pkey: 初始化好的密钥
 * 参数: u8 *input: 输入数据
 * 参数: u8 *output: 输出数据
 * 返回: int: 数据长度
 ********************************************************************************************/
int aes_encrypt(const AesKey* pkey, u8 *input, u8 *output);

/*********************************************************************************************
 * 名称: aes_decrypt
 * 功能: AES解密
 * 参数: const AesKey* pkey: 初始化好的密钥
 * 参数: u8 *input: 输入数据
 * 参数: u8 *output: 输出数据
 * 返回: int: 数据长度
 ********************************************************************************************/
int aes_decrypt(const AesKey* pkey, u8 *input, u8 *output);

Aes.cpp

/*适合单片机的AES加解密
 * Aes.cpp
 *
 *  Created on: 2014年12月6日
 *      Author: houj
 */

//////////////////////////////////////////////////////////////////////
#include <string.h>
#include <stdio.h>
#include "Util.h"
#include "Aes.h"





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

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

static inline u8 gfmultby01(u8 b) {  //乘1
   return b;
}

static inline u8 gfmultby02(u8 b) { //乘2
   if (b < 0x80) {
      return (b << 1);
   }
   else {
      return ((b << 1) ^ (0x1b));
   }
}

static inline u8 gfmultby03(u8 b) {
   return (gfmultby02(b) ^ b); //GF域的加法运算就是异或
}

static inline u8 gfmultby09(u8 b) {
   return (gfmultby02(gfmultby02(gfmultby02(b))) ^ b);
}

static inline u8 gfmultby0b(u8 b) {
   return (gfmultby02(gfmultby02(gfmultby02(b))) ^ gfmultby02(b) ^ b);
}

static inline u8 gfmultby0d(u8 b) {
   return (gfmultby02(gfmultby02(gfmultby02(b))) ^ gfmultby02(gfmultby02(b)) ^ (b));
}

static inline u8 gfmultby0e(u8 b) {
   return (gfmultby02(gfmultby02(gfmultby02(b))) ^ gfmultby02(gfmultby02(b)) ^ gfmultby02(b));
}

static inline void RotWord4(u8 *ws) {  //左旋一位
   u8 t = ws[0];
   ws[0] = ws[1];
   ws[1] = ws[2];
   ws[2] = ws[3];
   ws[3] = t;
}

static void SubWord4(u8 *ws) {  //用替换表 Sbox 对一给定的一行密钥调度表 w[] 进行逐字节替换。
   ws[0] = Sbox[ws[0] >> 4][ws[0] & 0x0f];
   ws[1] = Sbox[ws[1] >> 4][ws[1] & 0x0f];
   ws[2] = Sbox[ws[2] >> 4][ws[2] & 0x0f];
   ws[3] = Sbox[ws[3] >> 4][ws[3] & 0x0f];
}

static void ShiftRows(u8 State[][4]) {
   u8 temp[4][4];
   memcpy(temp, State, sizeof(temp));
   for (int r = 1; r < 4; ++r) {  // shift temp into State
      for (int c = 0; c < 4; ++c) {
         State[r][c] = temp[r][(c + r) & AES_NB_MASK];
      }
   }
}

static void MixColumns(u8 State[][4]) {
   u8 temp[4][4];
   memcpy(temp, State, sizeof(temp));
   for (int c = 0; c < 4; ++c) {
      State[0][c] = (gfmultby02(temp[0][c]) ^ gfmultby03(temp[1][c]) ^ gfmultby01(temp[2][c]) ^ gfmultby01(temp[3][c]));
      State[1][c] = (gfmultby01(temp[0][c]) ^ gfmultby02(temp[1][c]) ^ gfmultby03(temp[2][c]) ^ gfmultby01(temp[3][c]));
      State[2][c] = (gfmultby01(temp[0][c]) ^ gfmultby01(temp[1][c]) ^ gfmultby02(temp[2][c]) ^ gfmultby03(temp[3][c]));
      State[3][c] = (gfmultby03(temp[0][c]) ^ gfmultby01(temp[1][c]) ^ gfmultby01(temp[2][c]) ^ gfmultby02(temp[3][c]));
   }
}

static void SubBytes(u8 State[][4]) {
   for (int r = 0; r < 4; ++r) {
      for (int c = 0; c < 4; ++c) {
         State[r][c] = Sbox[(State[r][c] >> 4)][(State[r][c] & 0x0f)];
      }
   }
}

static void InvSubBytes(u8 State[][4]) {
   for (int r = 0; r < 4; ++r) {
      for (int c = 0; c < 4; ++c) {
         State[r][c] = iSbox[(State[r][c] >> 4)][(State[r][c] & 0x0f)];
      }
   }
}

static void InvShiftRows(u8 State[][4]) {
   u8 temp[4][4];
   memcpy(temp, State, sizeof(temp));
   for (int r = 1; r < 4; ++r) {  // shift temp into State
      for (int c = 0; c < 4; ++c) {
         State[r][(c + r) & AES_NB_MASK] = temp[r][c];
      }
   }
}

static void InvMixColumns(u8 State[][4]) {
   u8 temp[4][4];
   memcpy(temp, State, sizeof(temp));
   for (int c = 0; c < 4; ++c) {
      State[0][c] = (gfmultby0e(temp[0][c]) ^ gfmultby0b(temp[1][c]) ^ gfmultby0d(temp[2][c]) ^ gfmultby09(temp[3][c]));
      State[1][c] = (gfmultby09(temp[0][c]) ^ gfmultby0e(temp[1][c]) ^ gfmultby0b(temp[2][c]) ^ gfmultby0d(temp[3][c]));
      State[2][c] = (gfmultby0d(temp[0][c]) ^ gfmultby09(temp[1][c]) ^ gfmultby0e(temp[2][c]) ^ gfmultby0b(temp[3][c]));
      State[3][c] = (gfmultby0b(temp[0][c]) ^ gfmultby0d(temp[1][c]) ^ gfmultby09(temp[2][c]) ^ gfmultby0e(temp[3][c]));
   }
}

static void AddRoundKey(int round, u8 State[][4], const u8 keyw[][4]) {
   for (int r = 0; r < 4; ++r) {
      for (int c = 0; c < 4; ++c) {
         State[r][c] ^= keyw[(round * 4) + c][r];
      }
   }
}

/*********************************************************************************************
 * 名称: aes_initKey
 * 功能: 初始化AES密钥
 * 参数: AesKey* pkey: 打初始化的密钥
 * 参数: u8 *key: 密钥原始字节
 * 参数: int keysize: 密钥长度
 * 返回: boolean: 是否成功
 ********************************************************************************************/
boolean aes_initKey(AesKey* pkey, u8 *key, int keysize) {
   int Nk;    //代表以字为单位的块长
   switch (keysize) {
   case 16:
   case 128:
      Nk = 4;
      pkey->nc = 10;
      pkey->len = 16;
      break;
   case 24:
   case 192:
      Nk = 6;
      pkey->nc = 12;
      pkey->len = 24;
      break;
   case 32:
   case 256:
      Nk = 8;
      pkey->nc = 14;
      pkey->len = 32;
      break;
   default:
      pkey->nc = 0;
      pkey->len = 0;
      return false;
   }
//w[] 最初的 Nk (6) 行被作为种子,用原始密钥值
   for (int row = 0; row < Nk; ++row) {
      pkey->keyw[row][0] = key[4 * row];
      pkey->keyw[row][1] = key[4 * row + 1];
      pkey->keyw[row][2] = key[4 * row + 2];
      pkey->keyw[row][3] = key[4 * row + 3];
   }
   u8 temp[4];
   for (int row = Nk; row < AES_NB * (pkey->nc + 1); ++row) {
      temp[0] = pkey->keyw[row - 1][0];
      temp[1] = pkey->keyw[row - 1][1];
      temp[2] = pkey->keyw[row - 1][2];
      temp[3] = pkey->keyw[row - 1][3];
      if (row % Nk == 0) {
         RotWord4(temp);
         SubWord4(temp);
         temp[0] ^= Rcon[row  Nk][0];
         temp[1] ^= Rcon[row  Nk][1];
         temp[2] ^= Rcon[row  Nk][2];
         temp[3] ^= Rcon[row  Nk][3];
      }
      else if (Nk > 6 && (row % Nk == 4)) {
         SubWord4(temp);
      }
      pkey->keyw[row][0] = (pkey->keyw[row - Nk][0] ^ temp[0]);
      pkey->keyw[row][1] = (pkey->keyw[row - Nk][1] ^ temp[1]);
      pkey->keyw[row][2] = (pkey->keyw[row - Nk][2] ^ temp[2]);
      pkey->keyw[row][3] = (pkey->keyw[row - Nk][3] ^ temp[3]);
   }

   return true;
}

/*********************************************************************************************
 * 名称: aes_encrypt
 * 功能: AES加密
 * 参数: const AesKey* pkey: 初始化好的密钥
 * 参数: u8 *input: 输入数据
 * 参数: u8 *output: 输出数据
 * 返回: int: 数据长度
 ********************************************************************************************/
int aes_encrypt(const AesKey* pkey, u8 *input, u8 *output) {
   if (pkey->nc <= 0) {
      return 0;
   }
   u8 State[4][AES_NB];
   for (int i = 0; i < (4 * AES_NB); ++i) {
      State[i & 3][i >> 2] = input[i];        //this->State[i % 4][i / 4] = input[i];
   }
   AddRoundKey(0, State, pkey->keyw);

   for (int round = 1; round <= (pkey->nc - 1); ++round) {
      SubBytes(State);
      ShiftRows(State);
      MixColumns(State);
      AddRoundKey(round, State, pkey->keyw);
   }

   SubBytes(State);
   ShiftRows(State);
   AddRoundKey(pkey->nc, State, pkey->keyw);

   for (int i = 0; i < (4 * AES_NB); ++i) {
      output[i] = State[i & 3][i >> 2];  //this->State[i % 4][i / 4];
   }
   return pkey->len;
}

/*********************************************************************************************
 * 名称: aes_decrypt
 * 功能: AES解密
 * 参数: const AesKey* pkey: 初始化好的密钥
 * 参数: u8 *input: 输入数据
 * 参数: u8 *output: 输出数据
 * 返回: int: 数据长度
 ********************************************************************************************/
int aes_decrypt(const AesKey* pkey, u8 *input, u8 *output) {
   if (pkey->nc <= 0) {
      return 0;
   }
   u8 State[4][AES_NB];
   for (int i = 0; i < (4 * AES_NB); ++i) {
      State[i & 3][i >> 2] = input[i];
   }
   AddRoundKey(pkey->nc, State, pkey->keyw);

   for (int round = pkey->nc - 1; round >= 1; --round) {
      InvShiftRows(State);
      InvSubBytes(State);
      AddRoundKey(round, State, pkey->keyw);
      InvMixColumns(State);
   }

   InvShiftRows(State);
   InvSubBytes(State);
   AddRoundKey(0, State, pkey->keyw);

   for (int i = 0; i < (4 * AES_NB); ++i) {
      output[i] = State[i & 3][i >> 2];
   }
   return pkey->len;
}

//int main(int argc, char **argv) {
//   u8 ks[16];
//   memset(ks, 0x11, sizeof(ks));
//
//   AesKey pkey;
//   aes_initKey(&pkey, ks, 16);
//
//   u8 is[16];
//   u8 os[16];
//
//   memset(is, 0, sizeof(is));
//   memset(os, 0, sizeof(os));
//
//   aes_encrypt(&pkey, is, os);
//   printDatas("AES:", os, sizeof(os));  //AES:E0D541314E00102D6DFCA8BC007B6C8A
//
//   aes_decrypt(&pkey, is, os);
//   printDatas("AES:", os, sizeof(os));  //AES:5E749C2D64E5EF78279337670223FC08
//}

© 著作权归作者所有

h
粉丝 9
博文 81
码字总数 57985
作品 0
长沙
技术主管
私信 提问
AES加解密算法

前言 在很多项目中,对于安全性的要求是很高的,这就涉及到了各种加密,解密算法,常见的算法有MD5加密、DES加解密、字符串加解密、AES加解密等,下面来一起看一下AES加解密算法。 正文 AES(...

zt15732625878
2017/12/24
0
0
Java AES算法和UNIX下openssl之间的加解密

关于加解密的问题在网上搜索了很多资料,用JAVA AES和UNIX下openssl各自加解密都没什么问题,但是如果要JAVA AES算法的加密文件发送到UNIX下openssl解密,或者UNIX openssl加密的文件发给JAV...

wty530
2015/01/19
0
0
QT历程(一):与CryptoJs对应的AES加密

目的: 使用QT进行AES加密,能用CryptoJs进行AES解密。 说明: CryptoJs使用的AES加密文件为 aes.js 网上QT常用的AES加密方式 1. Crypto++库 2. Qca库 3. Botan库 4. 网友贡献的AES加密代码 ...

jiuyuehe
2016/05/31
239
0
Spring Boot JAR 安全加密运行工具 - XJar

XJar — Spring-Boot JAR 包加密运行工具,避免源码泄露以及反编译。 Spring Boot JAR安全加密运行工具,同时支持原生的JAR。 基于对JAR包内资源的加密以及拓展ClassLoader来构建的一套程序加...

不会钓鱼的兔子
2018/11/29
2.6K
0
Linux下ELF文件的加壳

【业务需求】 1.用c或者c++ 编写一个程序 实现elf文件的加密生成一个新的elf文件,为加壳的elf,加密算法用c,c++自带的AES加密。 2.用c或者c++ 写解密算法,实现对加壳过的elf进行解密。 3....

林志滨
2017/11/20
117
2

没有更多内容

加载失败,请刷新页面

加载更多

关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
6
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0
Docker容器实战(七) - 容器中进程视野下的文件系统

前两文中,讲了Linux容器最基础的两种技术 Namespace 作用是“隔离”,它让应用进程只能看到该Namespace内的“世界” Cgroups 作用是“限制”,它给这个“世界”围上了一圈看不见的墙 这么一...

JavaEdge
今天
8
0
文件访问和共享的方法介绍

在上一篇文章中,你了解到文件有三个不同的权限集。拥有该文件的用户有一个集合,拥有该文件的组的成员有一个集合,然后最终一个集合适用于其他所有人。在长列表(ls -l)中这些权限使用符号...

老孟的Linux私房菜
今天
7
0
面试套路题目

作者:抱紧超越小姐姐 链接:https://www.nowcoder.com/discuss/309292?type=3 来源:牛客网 面试时候的潜台词 抱紧超越小姐姐 编辑于 2019-10-15 16:14:56APP内打开赞 3 | 收藏 4 | 回复24 ...

MtrS
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部