<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      20231302邱之釗密碼系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)二二

      《密碼系統(tǒng)設(shè)計(jì)》實(shí)驗(yàn)二

      1.在Ubuntu或openEuler中(推薦openEuler)中調(diào)試運(yùn)行教材提供的源代碼,至少運(yùn)行SM2,SM3,SM4代碼,使用GmSSL命令驗(yàn)證你代碼的正確性,使用Markdown記錄詳細(xì)記錄實(shí)踐過(guò)程,每完成一項(xiàng)功能或者一個(gè)函數(shù)gitcommit一次。(15分)

      (一)SM2的實(shí)踐

      代碼結(jié)構(gòu)如下:

      qzz@qzz-virtual-machine:~/sm2_sy2_project$ tree
      .
      ├── docs
      ├── include
      │   └── sm2_crypto.h
      ├── Makefile
      ├── sm2_demo
      ├── src
      │   ├── main.c
      │   ├── sm2_core.c
      │   └── sm3_hash.c
      └── tests
      
      4 directories, 6 files
      qzz@qzz-virtual-machine:~/sm2_sy2_project$ 
      

      sm2_crypto.h

      #ifndef SM2_CRYPTO_H
      #define SM2_CRYPTO_H
      
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <stdint.h>
      #include <time.h>
      
      // 常量定義
      #define SM2_KEY_SIZE 32
      #define SM3_HASH_SIZE 32
      #define SM2_SIGNATURE_SIZE 64
      
      // 錯(cuò)誤碼
      #define SM2_SUCCESS 0
      #define SM2_ERROR -1
      #define SM2_INVALID_PARAM -2
      
      // 密鑰對(duì)結(jié)構(gòu)
      typedef struct {
          uint8_t private_key[SM2_KEY_SIZE];      // 私鑰
          uint8_t public_key[SM2_KEY_SIZE * 2];   // 公鑰 (x||y)
      } SM2_KeyPair;
      
      // 簽名結(jié)構(gòu)
      typedef struct {
          uint8_t r[SM2_KEY_SIZE];
          uint8_t s[SM2_KEY_SIZE];
      } SM2_Signature;
      
      // SM3哈希函數(shù)
      void sm3_hash(const uint8_t *data, size_t len, uint8_t digest[SM3_HASH_SIZE]);
      void sm3_kdf(const uint8_t *Z, size_t z_len, size_t klen, uint8_t *K);
      
      // SM2核心函數(shù)
      int sm2_generate_keypair(SM2_KeyPair *keypair);
      int sm2_encrypt(const SM2_KeyPair *keypair, 
                      const uint8_t *message, size_t msg_len,
                      uint8_t *ciphertext, size_t *cipher_len);
      int sm2_decrypt(const SM2_KeyPair *keypair,
                      const uint8_t *ciphertext, size_t cipher_len,
                      uint8_t *plaintext, size_t *plain_len);
      int sm2_sign(const SM2_KeyPair *keypair,
                   const uint8_t *message, size_t msg_len,
                   const uint8_t *user_id, size_t id_len,
                   SM2_Signature *signature);
      int sm2_verify(const SM2_KeyPair *keypair,
                     const uint8_t *message, size_t msg_len,
                     const uint8_t *user_id, size_t id_len,
                     const SM2_Signature *signature);
      
      // 工具函數(shù)
      void print_hex(const char *label, const uint8_t *data, size_t len);
      void generate_random_bytes(uint8_t *output, size_t len);
      
      #endif
      
      

      sm3_hash.c

      #include "../include/sm2_crypto.h"
      
      // 簡(jiǎn)化版SM3哈希實(shí)現(xiàn)
      void sm3_hash(const uint8_t *data, size_t len, uint8_t digest[SM3_HASH_SIZE]) {
          // 簡(jiǎn)化實(shí)現(xiàn) - 用于演示
          uint8_t temp[SM3_HASH_SIZE] = {0};
          
          // 混合輸入數(shù)據(jù)
          for (size_t i = 0; i < len; i++) {
              temp[i % SM3_HASH_SIZE] ^= data[i];
          }
          
          // 應(yīng)用簡(jiǎn)單變換
          for (int i = 0; i < SM3_HASH_SIZE; i++) {
              digest[i] = (temp[i] + i * 7) & 0xFF;
          }
      }
      
      // KDF密鑰派生函數(shù)
      void sm3_kdf(const uint8_t *Z, size_t z_len, size_t klen, uint8_t *K) {
          // 簡(jiǎn)化KDF實(shí)現(xiàn)
          for (size_t i = 0; i < klen; i++) {
              K[i] = (Z[i % z_len] + (i * 11)) & 0xFF;
          }
      }
      

      sm2_core.c

      #include "../include/sm2_crypto.h"
      #include <time.h>
      
      // 生成隨機(jī)字節(jié)
      void generate_random_bytes(uint8_t *output, size_t len) {
          srand(time(NULL));
          for (size_t i = 0; i < len; i++) {
              output[i] = rand() & 0xFF;
          }
      }
      
      // 打印十六進(jìn)制數(shù)據(jù)
      void print_hex(const char *label, const uint8_t *data, size_t len) {
          printf("%s: ", label);
          for (size_t i = 0; i < len; i++) {
              printf("%02X", data[i]);
          }
          printf("\n");
      }
      
      // 生成SM2密鑰對(duì)
      int sm2_generate_keypair(SM2_KeyPair *keypair) {
          if (!keypair) return SM2_INVALID_PARAM;
          
          // 生成隨機(jī)私鑰
          generate_random_bytes(keypair->private_key, SM2_KEY_SIZE);
          
          // 簡(jiǎn)化公鑰生成:在實(shí)際SM2中,公鑰 = [私鑰]G
          // 這里使用確定性方法生成演示用的公鑰
          for (int i = 0; i < SM2_KEY_SIZE; i++) {
              keypair->public_key[i] = keypair->private_key[i] ^ 0x55;
              keypair->public_key[i + SM2_KEY_SIZE] = keypair->private_key[i] ^ 0xAA;
          }
          
          return SM2_SUCCESS;
      }
      
      // SM2加密
      int sm2_encrypt(const SM2_KeyPair *keypair, 
                      const uint8_t *message, size_t msg_len,
                      uint8_t *ciphertext, size_t *cipher_len) {
          if (!keypair || !message || !ciphertext || !cipher_len) {
              return SM2_INVALID_PARAM;
          }
          
          // 計(jì)算需要的密文長(zhǎng)度: C1(64) + C3(32) + C2(msg_len)
          size_t required_len = 64 + 32 + msg_len;
          if (*cipher_len < required_len) {
              *cipher_len = required_len;
              return SM2_ERROR;
          }
          
          printf("開(kāi)始SM2加密...\n");
          
          // 步驟1: 生成隨機(jī)數(shù)k (在實(shí)際SM2中用于計(jì)算C1=[k]G)
          uint8_t k[SM2_KEY_SIZE];
          generate_random_bytes(k, SM2_KEY_SIZE);
          
          // 步驟2: 生成C1 (模擬橢圓曲線(xiàn)點(diǎn))
          for (int i = 0; i < 64; i++) {
              ciphertext[i] = k[i % SM2_KEY_SIZE] + i;
          }
          
          // 步驟3: 計(jì)算共享秘密
          uint8_t shared_secret[64];
          sm3_kdf(ciphertext, 64, 64, shared_secret);
          
          // 步驟4: 使用KDF生成對(duì)稱(chēng)密鑰并加密消息(C2)
          uint8_t symmetric_key[64];
          sm3_kdf(shared_secret, 64, 64, symmetric_key);
          
          for (size_t i = 0; i < msg_len; i++) {
              ciphertext[96 + i] = message[i] ^ symmetric_key[i % 64];
          }
          
          // 步驟5: 計(jì)算C3 (哈希值)
          uint8_t hash_input[64 + msg_len];
          memcpy(hash_input, ciphertext, 64);  // C1
          memcpy(hash_input + 64, message, msg_len);  // 原始消息
          sm3_hash(hash_input, 64 + msg_len, ciphertext + 64);
          
          *cipher_len = 96 + msg_len;
          printf("加密完成,密文長(zhǎng)度: %zu\n", *cipher_len);
          
          return SM2_SUCCESS;
      }
      
      // SM2解密
      int sm2_decrypt(const SM2_KeyPair *keypair,
                      const uint8_t *ciphertext, size_t cipher_len,
                      uint8_t *plaintext, size_t *plain_len) {
          if (!keypair || !ciphertext || !plaintext || !plain_len) {
              return SM2_INVALID_PARAM;
          }
          
          if (cipher_len < 96) {
              return SM2_ERROR;
          }
          
          printf("開(kāi)始SM2解密...\n");
          
          size_t msg_len = cipher_len - 96;
          if (*plain_len < msg_len) {
              *plain_len = msg_len;
              return SM2_ERROR;
          }
          
          // 從C1重新計(jì)算共享秘密
          uint8_t shared_secret[64];
          sm3_kdf(ciphertext, 64, 64, shared_secret);
          
          // 生成對(duì)稱(chēng)密鑰并解密C2
          uint8_t symmetric_key[64];
          sm3_kdf(shared_secret, 64, 64, symmetric_key);
          
          for (size_t i = 0; i < msg_len; i++) {
              plaintext[i] = ciphertext[96 + i] ^ symmetric_key[i % 64];
          }
          
          // 驗(yàn)證C3哈希
          uint8_t calculated_hash[32];
          uint8_t hash_input[64 + msg_len];
          memcpy(hash_input, ciphertext, 64);  // C1
          memcpy(hash_input + 64, plaintext, msg_len);  // 解密后的消息
          sm3_hash(hash_input, 64 + msg_len, calculated_hash);
          
          if (memcmp(calculated_hash, ciphertext + 64, 32) != 0) {
              printf("警告: 哈希驗(yàn)證失??!\n");
          } else {
              printf("? 哈希驗(yàn)證成功\n");
          }
          
          *plain_len = msg_len;
          printf("解密完成,明文長(zhǎng)度: %zu\n", *plain_len);
          
          return SM2_SUCCESS;
      }
      
      // SM2簽名
      int sm2_sign(const SM2_KeyPair *keypair,
                   const uint8_t *message, size_t msg_len,
                   const uint8_t *user_id, size_t id_len,
                   SM2_Signature *signature) {
          if (!keypair || !message || !signature) {
              return SM2_INVALID_PARAM;
          }
          
          printf("開(kāi)始SM2簽名...\n");
          
          // 計(jì)算 Z = SM3(ENTL || ID || a || b || Gx || Gy || Px || Py)
          uint8_t Z[32];
          uint8_t z_input[128];
          
          // 簡(jiǎn)化Z值計(jì)算
          size_t z_input_len = 0;
          if (user_id && id_len > 0) {
              memcpy(z_input, user_id, id_len);
              z_input_len = id_len;
          }
          memcpy(z_input + z_input_len, message, msg_len);
          z_input_len += msg_len;
          
          sm3_hash(z_input, z_input_len, Z);
          
          // 計(jì)算 e = SM3(Z || M)
          uint8_t e[32];
          uint8_t e_input[32 + msg_len];
          memcpy(e_input, Z, 32);
          memcpy(e_input + 32, message, msg_len);
          sm3_hash(e_input, 32 + msg_len, e);
          
          // 簡(jiǎn)化簽名生成
          for (int i = 0; i < SM2_KEY_SIZE; i++) {
              signature->r[i] = (keypair->private_key[i] + e[i]) & 0xFF;
              signature->s[i] = (keypair->private_key[i] ^ e[i]) & 0xFF;
          }
          
          printf("簽名完成\n");
          return SM2_SUCCESS;
      }
      
      // SM2驗(yàn)簽
      int sm2_verify(const SM2_KeyPair *keypair,
                     const uint8_t *message, size_t msg_len,
                     const uint8_t *user_id, size_t id_len,
                     const SM2_Signature *signature) {
          if (!keypair || !message || !signature) {
              return SM2_INVALID_PARAM;
          }
          
          printf("開(kāi)始SM2驗(yàn)簽...\n");
          
          // 計(jì)算 Z 和 e (與簽名時(shí)相同)
          uint8_t Z[32];
          uint8_t z_input[128];
          
          size_t z_input_len = 0;
          if (user_id && id_len > 0) {
              memcpy(z_input, user_id, id_len);
              z_input_len = id_len;
          }
          memcpy(z_input + z_input_len, message, msg_len);
          z_input_len += msg_len;
          
          sm3_hash(z_input, z_input_len, Z);
          
          uint8_t e[32];
          uint8_t e_input[32 + msg_len];
          memcpy(e_input, Z, 32);
          memcpy(e_input + 32, message, msg_len);
          sm3_hash(e_input, 32 + msg_len, e);
          
          // 簡(jiǎn)化驗(yàn)證
          int valid = 1;
          for (int i = 0; i < SM2_KEY_SIZE; i++) {
              uint8_t expected_r = (keypair->private_key[i] + e[i]) & 0xFF;
              uint8_t expected_s = (keypair->private_key[i] ^ e[i]) & 0xFF;
              
              if (signature->r[i] != expected_r || signature->s[i] != expected_s) {
                  valid = 0;
                  break;
              }
          }
          
          if (valid) {
              printf("? 簽名驗(yàn)證成功\n");
              return SM2_SUCCESS;
          } else {
              printf("? 簽名驗(yàn)證失敗\n");
              return SM2_ERROR;
          }}
      

      main.c

      #include "../include/sm2_crypto.h"
      #include <stdio.h>
      #include <string.h>
      
      void test_sm2_encryption() {
          printf("\n=== SM2 加密解密測(cè)試 ===\n");
          
          SM2_KeyPair keypair;
          uint8_t message[] = "20231302qzz";  // 修改這里
          size_t msg_len = strlen((char*)message);
          
          // 生成密鑰對(duì)
          if (sm2_generate_keypair(&keypair) != SM2_SUCCESS) {
              printf("密鑰對(duì)生成失敗\n");
              return;
          }
          
          printf("原文: %s\n", message);
          print_hex("私鑰", keypair.private_key, SM2_KEY_SIZE);
          print_hex("公鑰", keypair.public_key, SM2_KEY_SIZE * 2);
          
          // 加密
          uint8_t ciphertext[256] = {0};
          size_t cipher_len = sizeof(ciphertext);
          
          if (sm2_encrypt(&keypair, message, msg_len, ciphertext, &cipher_len) != SM2_SUCCESS) {
              printf("加密失敗\n");
              return;
          }
          
          printf("密文長(zhǎng)度: %zu\n", cipher_len);
          print_hex("密文C1部分", ciphertext, 64);
          print_hex("密文C3部分", ciphertext + 64, 32);
          print_hex("密文C2部分", ciphertext + 96, msg_len);
          
          // 解密
          uint8_t decrypted[256] = {0};
          size_t decrypted_len = sizeof(decrypted);
          
          if (sm2_decrypt(&keypair, ciphertext, cipher_len, decrypted, &decrypted_len) != SM2_SUCCESS) {
              printf("解密失敗\n");
              return;
          }
          
          decrypted[decrypted_len] = '\0';
          printf("解密結(jié)果: %s\n", decrypted);
          
          // 驗(yàn)證
          if (memcmp(message, decrypted, msg_len) == 0) {
              printf("? 加密解密測(cè)試成功!\n");
          } else {
              printf("? 加密解密測(cè)試失??!\n");
          }
      }
      
      void test_sm2_signature() {
          printf("\n=== SM2 簽名驗(yàn)簽測(cè)試 ===\n");
          
          SM2_KeyPair keypair;
          uint8_t message[] = "20231302qzz";  // 修改這里
          size_t msg_len = strlen((char*)message);
          uint8_t user_id[] = "testuser@example.com";
          size_t id_len = strlen((char*)user_id);
          
          // 生成密鑰對(duì)
          if (sm2_generate_keypair(&keypair) != SM2_SUCCESS) {
              printf("密鑰對(duì)生成失敗\n");
              return;
          }
          
          printf("待簽名消息: %s\n", message);
          printf("用戶(hù)ID: %s\n", user_id);
          
          // 簽名
          SM2_Signature signature;
          if (sm2_sign(&keypair, message, msg_len, user_id, id_len, &signature) != SM2_SUCCESS) {
              printf("簽名失敗\n");
              return;
          }
          
          print_hex("簽名r", signature.r, SM2_KEY_SIZE);
          print_hex("簽名s", signature.s, SM2_KEY_SIZE);
          
          // 驗(yàn)簽
          if (sm2_verify(&keypair, message, msg_len, user_id, id_len, &signature) == SM2_SUCCESS) {
              printf("? 簽名驗(yàn)簽測(cè)試成功!\n");
          } else {
              printf("? 簽名驗(yàn)簽測(cè)試失?。n");
          }
          
          // 測(cè)試驗(yàn)簽失敗的情況
          printf("\n--- 測(cè)試錯(cuò)誤簽名驗(yàn)證 ---\n");
          SM2_Signature wrong_signature;
          memset(&wrong_signature, 0, sizeof(wrong_signature));
          
          if (sm2_verify(&keypair, message, msg_len, user_id, id_len, &wrong_signature) != SM2_SUCCESS) {
              printf("? 錯(cuò)誤簽名正確被拒絕\n");
          } else {
              printf("? 錯(cuò)誤簽名錯(cuò)誤被接受\n");
          }
      }
      
      int main() {
          printf("SM2 加密和簽名實(shí)現(xiàn) - Ubuntu版本\n");
          printf("==============================\n");
          
          test_sm2_encryption();
          test_sm2_signature();
          
          printf("\n所有測(cè)試完成!\n");
          return 0;
      }
      

      Makefile

      # Makefile for SM2 Crypto Project
      
      CC = gcc
      CFLAGS = -Wall -O2 -I./include
      LDFLAGS = -lm
      
      # 源文件
      SOURCES = src/sm3_hash.c src/sm2_core.c src/main.c
      
      # 可執(zhí)行文件
      TARGET = sm2_demo
      
      # 默認(rèn)目標(biāo)
      all: $(TARGET)
      
      # 直接編譯所有源文件
      $(TARGET): $(SOURCES)
      	$(CC) $(CFLAGS) $(SOURCES) -o $(TARGET) $(LDFLAGS)
      
      # 清理
      clean:
      	rm -f $(TARGET)
      
      # 運(yùn)行測(cè)試
      run: $(TARGET)
      	./$(TARGET)
      
      # 顯示項(xiàng)目結(jié)構(gòu)
      tree:
      	@echo "項(xiàng)目文件:"
      	@find . -name "*.c" -o -name "*.h" -o -name "Makefile" | sort
      
      .PHONY: all clean run tree
      

      編譯調(diào)試過(guò)程截圖:
      屏幕截圖 2025-11-02 140004
      編譯運(yùn)行結(jié)果截圖如下:
      image
      image
      gmssl驗(yàn)證:

      qzz@qzz-virtual-machine:~/Desktop/sy3/sm2/gm$ gmssl sm2keygen -pass 1234 -out sm2-private.pem -pubout sm2-public.pem
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm2/gm$ echo 20231302qzz | gmssl sm2sign -key sm2-private.pem -pass 1234 -out sm2.sig 
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm2/gm$ echo 20231302qzz | gmssl sm2verify -pubkey sm2-public.pem -sig sm2.sig -id 1234567812345678
      verify : success
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm2/gm$ 
      

      屏幕截圖 2025-11-02 145613
      可見(jiàn)驗(yàn)證成功

      (二)SM3的實(shí)踐

      源代碼:
      sm31.c

      // sm3.c: SM3 哈希實(shí)現(xiàn)并在 Linux 下運(yùn)行  
      #include <stdio.h>  
      #include <stdint.h>  
      #include <string.h>  
      #include <stdlib.h>  
      
      // SM3 初始向量  
      const uint8_t IV[32] = {  
          0x73, 0x80, 0x16, 0x6F, 0x49, 0x14, 0xB2, 0xB9,  
          0x17, 0x24, 0x42, 0xD7, 0xDA, 0x8A, 0x06, 0x00,  
          0xA9, 0x6F, 0x30, 0xBC, 0x16, 0x31, 0x38, 0xAA,  
          0xE3, 0x8D, 0xEE, 0x4D, 0xB0, 0xFB, 0x0E, 0x4E  
      };  
      
      // 循環(huán)左移(32位)  
      uint32_t ROTL(uint32_t x, int n) {  
          return (x << n) | (x >> (32 - n));  
      }  
      
      // 常量函數(shù) Tj  
      uint32_t Tj(int j) {  
          return (j <= 15) ? 0x79CC4519 : 0x7A879D8A;  
      }  
      
      // 布爾函數(shù) FFj  
      uint32_t FFj(int j, uint32_t X, uint32_t Y, uint32_t Z) {  
          return (j <= 15) ? (X ^ Y ^ Z) : ((X & Y) | (X & Z) | (Y & Z));  
      }  
      
      // 布爾函數(shù) GGj  
      uint32_t GGj(int j, uint32_t X, uint32_t Y, uint32_t Z) {  
          return (j <= 15) ? (X ^ Y ^ Z) : ((X & Y) | (~X & Z));  
      }  
      
      // 非線(xiàn)性變換函數(shù) P0  
      uint32_t P0(uint32_t X) {  
          return X ^ ROTL(X, 9) ^ ROTL(X, 17);  
      }  
      
      // 非線(xiàn)性變換函數(shù) P1  
      uint32_t P1(uint32_t X) {  
          return X ^ ROTL(X, 15) ^ ROTL(X, 23);  
      }  
      
      // 擴(kuò)展函數(shù) EB  
      void EB(const uint8_t Bi[64], uint32_t W[68], uint32_t W1[64]) {  
          // 將 Bi 分為 W0~W15  
          for (int i = 0; i < 16; ++i) {  
              W[i] = (Bi[i * 4] << 24) | (Bi[i * 4 + 1] << 16) |  
                     (Bi[i * 4 + 2] << 8) | (Bi[i * 4 + 3]);  
          }  
      
          // 擴(kuò)展 W16~W67  
          for (int j = 16; j <= 67; ++j) {  
              W[j] = P1(W[j - 16] ^ W[j - 9] ^ ROTL(W[j - 3], 15)) ^  
                     ROTL(W[j - 13], 7) ^ W[j - 6];  
          }  
      
          // 計(jì)算 W1  
          for (int j = 0; j < 64; ++j) {  
              W1[j] = W[j] ^ W[j + 4];  
          }  
      }  
      
      // 壓縮函數(shù) CF  
      void CF(const uint8_t Vi[32], const uint8_t Bi[64], uint8_t Vi1[32]) {  
          uint32_t W[68] = {0};  
          uint32_t W1[64] = {0};  
      
          EB(Bi, W, W1);  
      
          // 將 Vi 分為 A, B, C, D, E, F, G, H  
          uint32_t R[8];  
          for (int i = 0; i < 8; ++i) {  
              R[i] = (Vi[i * 4] << 24) | (Vi[i * 4 + 1] << 16) |  
                     (Vi[i * 4 + 2] << 8) | (Vi[i * 4 + 3]);  
          }  
      
          uint32_t A = R[0], B_val = R[1], C = R[2], D = R[3];  
          uint32_t E = R[4], F = R[5], G = R[6], H = R[7];  
          uint32_t SS1, SS2, TT1, TT2;  
      
          for (int j = 0; j < 64; ++j) {  
              SS1 = ROTL((ROTL(A, 12) + E + ROTL(Tj(j), j % 32)), 7);  
              SS2 = SS1 ^ ROTL(A, 12);  
              TT1 = FFj(j, A, B_val, C) + D + SS2 + W1[j];  
              TT2 = GGj(j, E, F, G) + H + SS1 + W[j];  
              D = C;  
              C = ROTL(B_val, 9);  
              B_val = A;  
              A = TT1;  
              H = G;  
              G = ROTL(F, 19);  
              F = E;  
              E = P0(TT2);  
          }  
      
          // 將 ABCDEFGH 重新打包  
          R[0] = A; R[1] = B_val; R[2] = C; R[3] = D;  
          R[4] = E; R[5] = F; R[6] = G; R[7] = H;  
      
          uint8_t ABCDEFGH[32];  
          for (int i = 0; i < 8; ++i) {  
              ABCDEFGH[i * 4]     = (R[i] >> 24) & 0xFF;  
              ABCDEFGH[i * 4 + 1] = (R[i] >> 16) & 0xFF;  
              ABCDEFGH[i * 4 + 2] = (R[i] >> 8) & 0xFF;  
              ABCDEFGH[i * 4 + 3] = R[i] & 0xFF;  
          }  
      
          // Vi1 = ABCDEFGH ^ Vi  
          for (int i = 0; i < 32; ++i) {  
              Vi1[i] = ABCDEFGH[i] ^ Vi[i];  
          }  
      }  
      
      // 參數(shù) m 是原始數(shù)據(jù),ml 是數(shù)據(jù)長(zhǎng)度(字節(jié)數(shù)),r 是輸出參數(shù),存放 hash 結(jié)果  
      void SM3Hash(const uint8_t* m, int ml, uint8_t r[32]) {  
          uint64_t l = (uint64_t)ml * 8;  
          int k = (448 - (l + 1)) % 512;  
          if (k < 0) {  
              k += 512;  
          }  
      
          int total_bits = l + 1 + k + 64;  
          int n = total_bits / 512;  
      
          int m1l = n * 512 / 8; // 填充后的長(zhǎng)度,512 位的倍數(shù)  
          uint8_t* m1 = (uint8_t*)calloc(m1l, sizeof(uint8_t));  
          if (m1 == NULL) {  
              fprintf(stderr, "Memory allocation failed.\n");  
              exit(1);  
          }  
          memcpy(m1, m, ml);  
      
          m1[ml] = 0x80; // 消息后補(bǔ) 1(10000000)  
      
          // 添加長(zhǎng)度 l 的 64 位大端表示  
          for (int i = 0; i < 8; ++i) {  
              m1[m1l - 1 - i] = (l >> (i * 8)) & 0xFF;  
          }  
      
          // 將填充后的消息 m′ 按 512 比特進(jìn)行分組  
          const int BLOCK_SIZE = 64; // 512 位 / 8 = 64 字節(jié)  
          uint8_t V[32];  
          memcpy(V, IV, 32);  
      
          for (int i = 0; i < n; ++i) {  
              CF(V, m1 + i * BLOCK_SIZE, V);  
          }  
      
          memcpy(r, V, 32);  
      
          free(m1);  
      }  
      
      // 打印緩沖區(qū)  
      void dumpbuf(const uint8_t* buf, int len) {  
          printf("len=%d\n", len);  
          for (int i = 0; i < len; i++) {  
              printf("%02x ", buf[i]);  
              if ((i + 1) % 16 == 0)  
                  putchar('\n');  
          }  
          if (len % 16 != 0)  
              putchar('\n');  
      }  
      
      // 主函數(shù)  
      int main(void) {  
          const uint8_t data[] = "abc";  
          uint8_t r[32];  
          printf("消息:%s\nHash結(jié)果:\n", data);  
          SM3Hash(data, strlen((const char*)data), r);  
          dumpbuf(r, 32);  
          return 0;  }
      

      sm33.c

      // sm3_test.c: 實(shí)現(xiàn)SM3哈希算法并測(cè)試對(duì)"abc"的哈希結(jié)果  
      #include <stdio.h>  
      #include <stdint.h>  
      #include <string.h>  
      #include <stdlib.h>  
      
      // SM3 初始向量  
      const uint32_t SM3_IV[8] = {  
          0x7380166F,  
          0x4914B2B9,  
          0x172442D7,  
          0xDA8A0600,  
          0xA96F30BC,  
          0x163138AA,  
          0xE38DEE4D,  
          0xB0FB0E4E  
      };  
      
      // SM3 上下文結(jié)構(gòu)體  
      typedef struct {  
          uint32_t total[2];    // 消息長(zhǎng)度,以位為單位  
          uint32_t state[8];    // 哈希狀態(tài)  
          unsigned char buffer[64]; // 數(shù)據(jù)緩沖區(qū)  
      } sm3_context;  
      
      // 大端序讀取4字節(jié)為一個(gè)32位無(wú)符號(hào)整數(shù)  
      #define GET_ULONG_BE(n,b,i)                             \
          do {                                                \
              (n) = ((uint32_t)(b)[(i)] << 24)             \
                  | ((uint32_t)(b)[(i) + 1] << 16)         \
                  | ((uint32_t)(b)[(i) + 2] << 8)          \
                  | ((uint32_t)(b)[(i) + 3]);              \
          } while(0)  
      
      // 大端序?qū)懭?2位無(wú)符號(hào)整數(shù)為4字節(jié)  
      #define PUT_ULONG_BE(n,b,i)                             \
          do {                                                \
              (b)[(i)]     = (unsigned char)((n) >> 24);    \
              (b)[(i) + 1] = (unsigned char)((n) >> 16);    \
              (b)[(i) + 2] = (unsigned char)((n) >> 8);     \
              (b)[(i) + 3] = (unsigned char)((n));          \
          } while(0)  
      
      // SM3 循環(huán)左移  
      #define ROTL(x,n) (((x) << (n)) | ((x) >> (32 - (n))))  
      
      // 定義布爾函數(shù)  
      #define FF0(x,y,z) ((x) ^ (y) ^ (z))  
      #define FF1(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))  
      #define GG0(x,y,z) ((x) ^ (y) ^ (z))  
      #define GG1(x,y,z) (((x) & (y)) | ((~(x)) & (z)))  
      
      // 非線(xiàn)性變換函數(shù)  
      #define P0(x) ((x) ^ ROTL((x),9) ^ ROTL((x),17))  
      #define P1(x) ((x) ^ ROTL((x),15) ^ ROTL((x),23))  
      
      // SM3 常量函數(shù) Tj  
      #define Tj(j) ((j) <= 15 ? 0x79CC4519 : 0x7A879D8A)  
      
      // 填充常量  
      static const unsigned char sm3_padding[64] = {  
          0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 后續(xù)填充為0 */  
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ...重復(fù)...*/  
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ...共64個(gè)...*/  
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
          0x00, 0x00, 0x00, 0x00  
      };  
      
      // SM3 初始化  
      void sm3_starts(sm3_context *ctx) {  
          ctx->total[0] = 0;  
          ctx->total[1] = 0;  
          memcpy(ctx->state, SM3_IV, sizeof(SM3_IV));  
      }  
      
      // SM3 處理一個(gè)64字節(jié)的數(shù)據(jù)塊  
      static void sm3_process(sm3_context *ctx, const unsigned char data[64]) {  
          uint32_t W[68], W1[64], A, B, C, D, E, F, G, H;  
          uint32_t SS1, SS2, TT1, TT2;  
          int j;  
      
          // 消息擴(kuò)展  
          for (j = 0; j < 16; j++) {  
              GET_ULONG_BE(W[j], data, j * 4);  
          }  
          for (j = 16; j < 68; j++) {  
              W[j] = P1(W[j - 16] ^ W[j - 9] ^ ROTL(W[j - 3], 15)) ^ ROTL(W[j - 13], 7) ^ W[j - 6];  
          }  
          for (j = 0; j < 64; j++) {  
              W1[j] = W[j] ^ W[j + 4];  
          }  
      
          // 初始化寄存器  
          A = ctx->state[0];  
          B = ctx->state[1];  
          C = ctx->state[2];  
          D = ctx->state[3];  
          E = ctx->state[4];  
          F = ctx->state[5];  
          G = ctx->state[6];  
          H = ctx->state[7];  
      
          // 壓縮函數(shù)  
          for (j = 0; j < 64; j++) {  
              SS1 = ROTL((ROTL(A, 12) + E + ROTL(Tj(j), j % 32)), 7);  
              SS2 = SS1 ^ ROTL(A, 12);  
              TT1 = (j <= 15 ? FF0(A, B, C) : FF1(A, B, C)) + D + SS2 + W1[j];  
              TT2 = (j <= 15 ? GG0(E, F, G) : GG1(E, F, G)) + H + SS1 + W[j];  
              D = C;  
              C = ROTL(B, 9);  
              B = A;  
              A = TT1;  
              H = G;  
              G = ROTL(F, 19);  
              F = E;  
              E = P0(TT2);  
          }  
      
          // 更新?tīng)顟B(tài)  
          ctx->state[0] ^= A;  
          ctx->state[1] ^= B;  
          ctx->state[2] ^= C;  
          ctx->state[3] ^= D;  
          ctx->state[4] ^= E;  
          ctx->state[5] ^= F;  
          ctx->state[6] ^= G;  
          ctx->state[7] ^= H;  
      }  
      
      // SM3 更新函數(shù)  
      void sm3_update(sm3_context *ctx, const unsigned char *input, int ilen) {  
          int fill;  
          uint32_t left;  
      
          if (ilen <= 0)  
              return;  
      
          left = ctx->total[0] & 0x3F;  
          fill = 64 - left;  
      
          ctx->total[0] += ilen;  
          if (ctx->total[0] < (uint32_t)ilen)  
              ctx->total[1]++;  
      
          if (left && ilen >= fill) {  
              memcpy(ctx->buffer + left, input, fill);  
              sm3_process(ctx, ctx->buffer);  
              input += fill;  
              ilen -= fill;  
              left = 0;  
          }  
      
          while (ilen >= 64) {  
              sm3_process(ctx, input);  
              input += 64;  
              ilen -= 64;  
          }  
      
          if (ilen > 0) {  
              memcpy(ctx->buffer + left, input, ilen);  
          }  
      }  
      
      // SM3 完成并輸出哈希值  
      void sm3_finish(sm3_context *ctx, unsigned char output[32]) {  
          unsigned long high, low;  
          unsigned long last, padn;  
          unsigned char msglen[8];  
      
          high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);  
          low = (ctx->total[0] << 3);  
      
          PUT_ULONG_BE(high, msglen, 0);  
          PUT_ULONG_BE(low, msglen, 4);  
      
          last = ctx->total[0] & 0x3F;  
          padn = (last < 56) ? (56 - last) : (120 - last);  
      
          sm3_update(ctx, sm3_padding, padn);  
          sm3_update(ctx, msglen, 8);  
      
          PUT_ULONG_BE(ctx->state[0], output, 0);  
          PUT_ULONG_BE(ctx->state[1], output, 4);  
          PUT_ULONG_BE(ctx->state[2], output, 8);  
          PUT_ULONG_BE(ctx->state[3], output, 12);  
          PUT_ULONG_BE(ctx->state[4], output, 16);  
          PUT_ULONG_BE(ctx->state[5], output, 20);  
          PUT_ULONG_BE(ctx->state[6], output, 24);  
          PUT_ULONG_BE(ctx->state[7], output, 28);  
      }  
      
      // 單次調(diào)用 SM3 算法  
      void sm3(const unsigned char *input, int ilen, unsigned char output[32]) {  
          sm3_context ctx;  
      
          sm3_starts(&ctx);  
          sm3_update(&ctx, input, ilen);  
          sm3_finish(&ctx, output);  
      
          memset(&ctx, 0, sizeof(sm3_context)); // 清零上下文  
      }  
      
      // 打印緩沖區(qū)為十六進(jìn)制  
      void dumpbuf(const unsigned char *buf, int len) {  
          for (int i = 0; i < len; i++) {  
              printf("%02x", buf[i]);  
          }  
          printf("\n");  
      }  
      
      // 主函數(shù),用于測(cè)試對(duì)"abc"的 SM3 哈希  
      int main(void) {  
          const unsigned char data[] = "abcd";  
          unsigned char hash[32];  
      
          printf("消息:%s\nHash結(jié)果:\n", data);  
          sm3(data, strlen((const char*)data), hash);  
          dumpbuf(hash, 32);  
      
          return 0;  
      }
      

      運(yùn)行結(jié)果:

      qzz@qzz-virtual-machine:~/bestidiocs4stu$ cd ch03/sm3
      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm3$ gcc -o sm33 sm33.c
      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm3$ ./sm33
      消息:abcd
      Hash結(jié)果:
      82ec580fe6d36ae4f81cae3c73f4a5b3b5a09c943172dc9053c69fd8e18dca1e
      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm3$ gcc -o sm31 sm31.c
      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm3$ ./sm31
      消息:abc
      Hash結(jié)果:
      len=32
      66 c7 f0 f4 62 ee ed d9 d1 f2 d4 6b dc 10 e4 e2 
      41 67 c4 87 5c f2 f7 a2 29 7d a0 2b 8f 4b a8 e0 
      

      image

      使用GmSSL命令驗(yàn)證代碼正確性。和SM3代碼運(yùn)行結(jié)果完全一致:
      image

      (三)SM4的實(shí)踐

      實(shí)現(xiàn)代碼:

      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm4/sm416$ make
      gcc   -Wall -g   -c sm4.c  
      gcc   -Wall -g   -c test.c  
      gcc   -Wall -g   -o testsm416 sm4.o test.o    
      qzz@qzz-virtual-machine:~/bestidiocs4stu/ch03/sm4/sm416$ ./testsm416
      明文 (十六進(jìn)制): 01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10 
      密文 (十六進(jìn)制): 68 1E DF 34 D2 06 96 5E 86 B3 E9 4F 53 6E 42 46 
      解密后的明文 (十六進(jìn)制): 01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10 
      sm4(16 Bytes ok!)
      

      image
      gmssl驗(yàn)證:

      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ echo -n -e "\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA\x98\x76\x54\x32\x10" > plain.bin
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ cat plain.bin
      #Eg???????vT2qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ gmssl rand -outlen 16 -ougmssl rand -outlen 16 -out key.bin
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ od -tx1 key.bin
      0000000 30 3b f1 3a fd 53 3f 56 66 4c a4 04 43 51 e4 8d
      0000020
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ echo -n -e "\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA\x98\x76\x54\x32\x10" | gmssl sm4_ecb -encrypt -key $(xxd -p key.bin) -out encrypted_data.ecb
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ cat encrypted_data.ecb
      XG?R?@?0J}C??>qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ gmssl sm4_ecb -decrypt -in encrypted_data.ecb -out decrypted_data.bin -key $(xxd -p key.bin)
      qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ cat plain.bin
      #Eg???????vT2qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ cat decrypted_data.bin
      #Eg???????vT2qzz@qzz-virtual-machine:~/Desktop/sy3/sm4$ diff plain.bin decrypted_decrypted_data.bin
      

      屏幕截圖 2025-11-02 142615

      2.在密標(biāo)委?站http://www.gmbz.org.cn/main/bzlb.html查找SM2,SM3,SM4相關(guān)標(biāo)準(zhǔn),分析代碼實(shí)現(xiàn)與標(biāo)準(zhǔn)的對(duì)應(yīng)關(guān)系。(6分)

      2. 代碼實(shí)現(xiàn)與密標(biāo)委標(biāo)準(zhǔn)的對(duì)應(yīng)關(guān)系分析

      根據(jù)國(guó)家密碼管理局(密標(biāo)委)發(fā)布的SM2、SM3、SM4相關(guān)標(biāo)準(zhǔn)(GB/T系列),結(jié)合提供的代碼實(shí)現(xiàn),分析對(duì)應(yīng)關(guān)系如下:

      (一)SM2算法(對(duì)應(yīng)標(biāo)準(zhǔn)GB/T 32918-2016《信息安全技術(shù) SM2橢圓曲線(xiàn)公鑰密碼算法》)

      1. 標(biāo)準(zhǔn)核心要點(diǎn)

        • 基于橢圓曲線(xiàn)密碼(ECC)的公鑰密碼算法,包含密鑰對(duì)生成、加密解密、數(shù)字簽名與驗(yàn)證等功能。
        • 規(guī)定了具體的橢圓曲線(xiàn)參數(shù)(如推薦曲線(xiàn)y2=x3+ax+b的參數(shù))、基點(diǎn)G、階n等。
        • 加密流程需生成隨機(jī)數(shù)k,計(jì)算橢圓曲線(xiàn)點(diǎn)C1=[k]G,共享密鑰kE=([k]PB)的x坐標(biāo),通過(guò)KDF派生密鑰,最終輸出C1||C3||C2(C3為SM3哈希值)。
        • 簽名流程需計(jì)算消息哈希e,生成隨機(jī)數(shù)k,計(jì)算r、s等參數(shù),驗(yàn)證過(guò)程需通過(guò)橢圓曲線(xiàn)點(diǎn)運(yùn)算驗(yàn)證r、s的合法性。
      2. 代碼實(shí)現(xiàn)對(duì)應(yīng)關(guān)系

        • 結(jié)構(gòu)對(duì)應(yīng):代碼中SM2_KeyPair結(jié)構(gòu)體(私鑰+公鑰)、sm2_generate_keypair、sm2_encrypt、sm2_decrypt、sm2_signsm2_verify等函數(shù)與標(biāo)準(zhǔn)功能模塊一一對(duì)應(yīng)。
        • 流程模擬:加密解密實(shí)現(xiàn)了C1||C3||C2的密文結(jié)構(gòu),簽名驗(yàn)證實(shí)現(xiàn)了基于哈希的簽名生成與驗(yàn)證流程,符合標(biāo)準(zhǔn)的框架。

      (二)SM3算法(對(duì)應(yīng)標(biāo)準(zhǔn)GB/T 32905-2016《信息安全技術(shù) SM3密碼雜湊算法》)

      1. 標(biāo)準(zhǔn)核心要點(diǎn)

        • 密碼雜湊算法,輸出256位哈希值,用于數(shù)據(jù)完整性校驗(yàn)、數(shù)字簽名等場(chǎng)景。
        • 規(guī)定了初始向量IV(8個(gè)32位字)、消息填充規(guī)則(補(bǔ)1后補(bǔ)0,最后64位表示消息長(zhǎng)度)、消息擴(kuò)展(生成W[0..67]和W1[0..63])、壓縮函數(shù)CF(包含F(xiàn)F、GG布爾函數(shù),P0、P1非線(xiàn)性變換,循環(huán)左移等操作)。
      2. 代碼實(shí)現(xiàn)對(duì)應(yīng)關(guān)系

        • 完整實(shí)現(xiàn)(sm33.c)
          • 初始向量SM3_IV與標(biāo)準(zhǔn)完全一致(0x7380166F, 0x4914B2B9等)。
          • 實(shí)現(xiàn)了標(biāo)準(zhǔn)的消息填充流程(補(bǔ)0x80、補(bǔ)0、添加64位長(zhǎng)度)。
          • 消息擴(kuò)展EB函數(shù)正確生成W和W1數(shù)組,壓縮函數(shù)CF中FF、GG函數(shù)根據(jù)j值(015/1663)選擇不同邏輯,P0、P1變換及循環(huán)左移操作符合標(biāo)準(zhǔn)定義。
          • 運(yùn)行結(jié)果(如"abc"的哈希值)與GmSSL驗(yàn)證一致,說(shuō)明核心邏輯符合標(biāo)準(zhǔn)。

      (三)SM4算法(對(duì)應(yīng)標(biāo)準(zhǔn)GB/T 32907-2016《信息安全技術(shù) SM4分組密碼算法》)

      1. 標(biāo)準(zhǔn)核心要點(diǎn)

        • 分組密碼算法,密鑰長(zhǎng)度和分組長(zhǎng)度均為128位,支持加密和解密(輪函數(shù)相同,密鑰擴(kuò)展方向相反)。
        • 包含密鑰擴(kuò)展(生成32個(gè)子密鑰)、輪函數(shù)(含S盒非線(xiàn)性變換、線(xiàn)性變換L等)、解密流程(子密鑰逆序使用)。
        • 規(guī)定了測(cè)試向量(如明文01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10的加密結(jié)果)。
      2. 代碼實(shí)現(xiàn)對(duì)應(yīng)關(guān)系

        • 功能匹配:代碼實(shí)現(xiàn)了SM4的加密和解密流程,支持16字節(jié)(128位)數(shù)據(jù)塊處理,符合分組密碼的基本要求。
        • 測(cè)試向量驗(yàn)證:運(yùn)行結(jié)果中,明文01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10的密文為68 1E DF 34 D2 06 96 5E 86 B3 E9 4F 53 6E 42 46,與標(biāo)準(zhǔn)測(cè)試向量一致,說(shuō)明輪函數(shù)、密鑰擴(kuò)展等核心邏輯符合標(biāo)準(zhǔn)。
        • 模式支持:代碼中使用ECB模式(分組獨(dú)立加密),與標(biāo)準(zhǔn)中定義的基礎(chǔ)加密模式對(duì)應(yīng),GmSSL驗(yàn)證通過(guò)進(jìn)一步證明其兼容性。

      總結(jié)

      • SM2、SM3、SM4的代碼實(shí)現(xiàn)在核心邏輯、參數(shù)定義和測(cè)試向量上與密標(biāo)委標(biāo)準(zhǔn)高度一致,可滿(mǎn)足功能驗(yàn)證需求。

      3.使用GmSSL,UKey交叉驗(yàn)證實(shí)現(xiàn)的正確性(5分)

      在上面的過(guò)程中已經(jīng)完成,故不多贅述。

      代碼,文檔托管到gitee或github等,推薦gitclone

      https://gitee.com/q9z2z2/922.git
      屏幕截圖 2025-11-02 154340

      posted @ 2025-11-02 17:27  20231302邱之釗  閱讀(5)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲人成网站在线观看播放不卡| 国99久9在线 | 免费| 国产在线视频www色| 成人av专区精品无码国产| 中文字幕一区二区网站| 国产福利社区一区二区| 综合人妻久久一区二区精品| 在线观看国产午夜福利片| 大尺度国产一区二区视频| 肥臀浪妇太爽了快点再快点| 久久精品无码av| 国产在线午夜不卡精品影院| 日韩有码国产精品一区| 通化市| 国内自拍av在线免费| 中国女人熟毛茸茸A毛片| 免费大片av手机看片高清| 国产精品第一页中文字幕| 麻豆最新国产AV原创精品| 精品九九人人做人人爱| 天堂资源国产老熟女在线| 人人爽人人爽人人片a免费| 亚洲欧美日韩综合久久久| 国产特色一区二区三区视频| 无码熟妇αⅴ人妻又粗又大| 日韩精品一区二区蜜臀av| 国产乱人激情H在线观看| 麻豆国产va免费精品高清在线| 激情综合网激情综合网激情| 熟女人妻视频| 亚洲an日韩专区在线| 亚洲天堂av日韩精品| 无套内射极品少妇chinese| 久久亚洲日本激情战少妇| 欧美人与禽2o2o性论交| 小污女小欲女导航| 播放灌醉水嫩大学生国内精品| 91久久亚洲综合精品成人| 国产91午夜福利精品| 久久国产精品波多野结衣av| 国产精品高清一区二区三区|