实用指南:c++ openssl 使用 DES(数据加密标准)进行加密和解密的基本操作

使用 DES(数据加密标准)进行加密和解密的基本操作,重点展示了 ECB 和 CBC 模式,并且通过篡改密文的方式来进行攻击。下面是对每个部分的详细解析。

1. 结构体 Slip

struct Slip
{
char from[16] = {
0
}
;
// 交易的发起者(例如 A => B)
char to[16] = {
0
}
;
// 交易的接收者(例如 B => A)
long
long amount = 0
;
// 交易金额
}
;
  • Slip 结构体存储了三部分数据:发起者 (from)、接收者 (to) 和交易金额 (amount)。
  • 这段数据需要加密并在后续的操作中进行篡改。

2. 全局变量:DES 密钥和密钥调度

static const_DES_cblock key = "1234567"
;
static DES_key_schedule key_sch;
  • key 是一个 8 字节的 DES 密钥,硬编码为 “1234567”。
  • key_sch 是 DES 密钥调度,它将密钥转换为 DES 算法可用的形式。

3. 加密函数 EnSlip

void EnSlip(
const Slip& s,
unsigned
char* out,
int &out_size)
{
int size =
sizeof(s)
;
auto p = (
const
unsigned
char*
)&s;
auto o = out;
DES_set_key(&key, &key_sch)
;
for (
int i = 0
; i < size; i += 8
)
{
DES_ecb_encrypt((const_DES_cblock*
)p, (DES_cblock*
)o, &key_sch, DES_ENCRYPT)
;
p += 8
;
o += 8
;
out_size += 8
;
}
}
  • EnSlip 负责对 Slip 数据进行加密。
  • 以 8 字节为单位处理 Slip 结构体的数据(DES 是块加密算法,每次处理 8 字节)。
  • DES_ecb_encrypt 用于在 ECB 模式下加密数据。
  • 每次加密后,将输入数据指针 p 和输出数据指针 o 移动 8 字节。

4. 解密函数 DeSlip

void DeSlip(
const
unsigned
char* in,
int size, Slip& s)
{
auto p = (
const
unsigned
char*
)in;
auto o = (
unsigned
char*
)&s;
DES_set_key(&key, &key_sch)
;
for (
int i = 0
; i < size; i += 8
)
{
DES_ecb_encrypt((const_DES_cblock*
)p, (DES_cblock*
)o, &key_sch, DES_DECRYPT)
;
p += 8
;
o += 8
;
}
}
  • DeSlip 用于解密加密后的 Slip 数据。
  • 它与 EnSlip 类似,不过使用了 DES_DECRYPT 进行解密。

5. 篡改密文函数 AttackSlip

void AttackSlip(
unsigned
char* out)
{
// 修改密文:交换 from 和 to
unsigned
char tmp[1024] = {
0
}
;
memcpy(tmp, out, 16
)
;
// 复制 from 部分
memcpy(out, out + 16
, 16
)
;
// 将 to 部分放到 from 的位置
memcpy(out + 16
, tmp, 16
)
;
// 将原来的 from 部分放到 to 的位置
}
  • AttackSlip 是一个简单的篡改密文的攻击方法,它交换了加密后的 from 和 to 字段。
  • 这种攻击显示了 ECB 模式的弱点,因为 ECB 模式在加密相同的数据块时会生成相同的密文,攻击者可以直接修改密文。

6. CBC 模式的加密函数 EnSlipCBC

void EnSlipCBC(
const Slip& s,
unsigned
char* out,
int& out_size)
{
int size =
sizeof(s)
;
auto p = (
const
unsigned
char*
)&s;
auto o = out;
DES_set_key(&key, &key_sch)
;
DES_cblock iv = {
0
}
;
// 初始化向量,设置为全零
out_size = size;
if (size % 8 != 0
)
{
// 补充0到 8 的倍数
out_size = size + (8 - size % 8
)
;
}
DES_cbc_encrypt(p, o,
sizeof(s)
, &key_sch, &iv, DES_ENCRYPT)
;
}
  • EnSlipCBC 使用 CBC 模式对 Slip 数据进行加密。
  • 如果数据长度不是 8 的倍数,则会填充零(补充到 8 字节的倍数)。
  • 使用 DES_cbc_encrypt 进行加密,其中需要提供初始化向量(IV)。在此处,IV 被初始化为全零。

7. CBC 模式的解密函数 DeSlipCBC

void DeSlipCBC(
const
unsigned
char* in,
int size, Slip& s)
{
DES_cblock iv = {
0
}
;
// 初始化向量
DES_set_key(&key, &key_sch)
;
DES_cbc_encrypt(in, (
unsigned
char*
)&s, size, &key_sch, &iv, DES_DECRYPT)
;
}
  • DeSlipCBC 用于解密 CBC 模式加密的数据。
  • 它使用与加密相同的 IV(此处为全零),并使用 DES_cbc_encrypt 解密数据。

8. 主函数 main

int main(
int argc,
char* argv[]
)
{
unsigned
char out[1024] = {
0
}
;
int out_size = 0
;
Slip s1 = {
"USER_A"
, "USER_B"
, 10000
}
;
cout <<
"s1 from:" << s1.from << endl;
cout <<
"s1 to:" << s1.to << endl;
cout <<
"s1 amount:" << s1.amount << endl;
EnSlip(s1, out, out_size)
;
cout <<
"En: " << out_size <<
" | " << out << endl;
// 攻击密文
AttackSlip(out)
;
Slip s2;
DeSlip(out, out_size, s2)
;
cout <<
"s2 from:" << s2.from << endl;
cout <<
"s2 to:" << s2.to << endl;
cout <<
"s2 amount:" << s2.amount << endl;
Slip s3;
EnSlipCBC(s1, out, out_size)
;
// 攻击密文
AttackSlip(out)
;
DeSlipCBC(out, out_size, s3)
;
cout <<
"s3 from:" << s3.from << endl;
cout <<
"s3 to:" << s3.to << endl;
cout <<
"s3 amount:" << s3.amount << endl;
getchar(
)
;
return 0
;
}
  • 在主函数中,首先创建了一个交易数据 s1(发起者 “USER_A”、接收者 “USER_B”、金额 10000)。
  • 对 s1 使用 ECB 模式进行加密,并输出加密后的密文。
  • 然后,调用 AttackSlip 攻击密文,交换 from 和 to 字段,并解密密文。
  • 同样,对 s1 使用 CBC 模式进行加密,攻击密文后,再使用 CBC 解密。

9. 攻击分析

  • ECB 模式的漏洞: 因为 ECB 模式对每个数据块独立加密,导致相同的数据块加密后密文相同,攻击者可以直接修改密文(例如交换 from 和 to 字段),从而篡改交易数据。
  • CBC 模式的优势: 虽然 CBC 模式对每个数据块进行依赖加密,增强了安全性,但在此代码中并没有使用认证机制,攻击者仍然可以通过篡改密文的一部分(如改变密文中的块顺序)影响解密结果。

完整代码

#
include <iostream>
  #
  include <openssl/des.h>
    #
    include <cstring>
      using
      namespace std;
      // 交易数据
      struct Slip
      {
      char from[16] = {
      0
      }
      ;
      // A=>B 10000
      char to[16] = {
      0
      }
      ;
      // 篡改为 B=>A 10000
      long
      long amount = 0
      ;
      }
      ;
      static const_DES_cblock key = "1234567"
      ;
      static DES_key_schedule key_sch;
      void EnSlip(
      const Slip &s,
      unsigned
      char *out,
      int &out_size)
      {
      int size =
      sizeof(s)
      ;
      auto p = (
      const
      unsigned
      char *
      )&s;
      auto o = out;
      DES_set_key(&key, &key_sch)
      ;
      for (
      int i = 0
      ; i < size; i += 8
      )
      {
      DES_ecb_encrypt((const_DES_cblock *
      )p, // 输入数据
      (DES_cblock *
      )o, // 输出数据
      &key_sch, // 秘钥
      DES_ENCRYPT // 1 加密
      )
      ;
      p += 8
      ;
      o += 8
      ;
      out_size += 8
      ;
      }
      // 补充数据。。。
      }
      void DeSlip(
      const
      unsigned
      char *in,
      int size, Slip &s)
      {
      auto p = (
      const
      unsigned
      char *
      )in;
      auto o = (
      unsigned
      char *
      )&s;
      DES_set_key(&key, &key_sch)
      ;
      for (
      int i = 0
      ; i < size; i += 8
      )
      {
      DES_ecb_encrypt((const_DES_cblock *
      )p, (DES_cblock *
      )o, &key_sch, DES_DECRYPT)
      ;
      p += 8
      ;
      o += 8
      ;
      }
      }
      void AttackSlip(
      unsigned
      char *out)
      {
      // 修改密文 from 和to 对调
      unsigned
      char tmp[1024] = {
      0
      }
      ;
      // from
      memcpy(tmp, out, 16
      )
      ;
      // to copy from
      memcpy(out, out + 16
      , 16
      )
      ;
      memcpy(out + 16
      , tmp, 16
      )
      ;
      }
      void EnSlipCBC(
      const Slip &s,
      unsigned
      char *out,
      int &out_size)
      {
      int size =
      sizeof(s)
      ;
      auto p = (
      const
      unsigned
      char *
      )&s;
      auto o = out;
      DES_set_key(&key, &key_sch)
      ;
      DES_cblock iv = {
      0
      }
      ;
      // 初始化向量
      out_size = size;
      // 数据如果不是8的倍数,会补0
      if (size % 8 != 0
      )
      {
      // 补充0
      out_size = size + (8 - size * 8
      )
      ;
      }
      DES_cbc_encrypt(
      p, // 输入
      o, // 输出
      sizeof(s)
      , // 输入数据的大小
      &key_sch, // 秘钥
      &iv, // 初始化向量 DES_cbc_encrypt 调用后值不变
      // DES_ncbc_encrypt 保存上次的值
      DES_ENCRYPT // 加密
      )
      ;
      }
      void DeSlipCBC(
      const
      unsigned
      char *in,
      int size, Slip &s)
      {
      DES_cblock iv = {
      0
      }
      ;
      // 初始化向量
      DES_set_key(&key, &key_sch)
      ;
      // 如果补0了 解密后无法知道实际大小,需要用户存储原数据大小
      DES_cbc_encrypt(in, (
      unsigned
      char *
      )&s, size, &key_sch, &iv, DES_DECRYPT)
      ;
      }
      int main(
      int argc,
      char *argv[]
      )
      {
      unsigned
      char out[1024] = {
      0
      }
      ;
      int out_size = 0
      ;
      Slip s1 = {
      "USER_A"
      , "USER_B"
      , 10000
      }
      ;
      cout <<
      "s1 from:" << s1.from << endl;
      cout <<
      "s1 to:" << s1.to << endl;
      cout <<
      "s1 amount:" << s1.amount << endl;
      EnSlip(s1, out, out_size)
      ;
      cout <<
      "En:" << out_size <<
      "|" << out << endl;
      // 攻击密文
      AttackSlip(out)
      ;
      Slip s2;
      DeSlip(out, out_size, s2)
      ;
      cout <<
      "s2 from:" << s2.from << endl;
      cout <<
      "s2 to:" << s2.to << endl;
      cout <<
      "s2 amount:" << s2.amount << endl;
      Slip s3;
      EnSlipCBC(s1, out, out_size)
      ;
      // 攻击密文
      AttackSlip(out)
      ;
      DeSlipCBC(out, out_size, s3)
      ;
      cout <<
      "s3 from:" << s3.from << endl;
      cout <<
      "s3 to:" << s3.to << endl;
      cout <<
      "s3 amount:" << s3.amount << endl;
      getchar(
      )
      ;
      return 0
      ;
      }
posted @ 2025-07-19 09:22  yjbjingcha  阅读(65)  评论(0)    收藏  举报