微信 MMTLS 协议详解(五):加密实现

news2025/4/1 19:09:15

常用的解密算法,对称非对称 加密,密钥协商, 带消息认证的加解密
#生成RSA 密钥对

void GenerateRsaKeypair(std::string& public_key,
  std::string& private_key)
{
  RSA* rsa = RSA_new();
  BIGNUM* bn = BN_new();

  // 生成 RSA 密钥对
  BN_set_word(bn, RSA_F4);
  RSA_generate_key_ex(rsa, 2048, bn, nullptr);

  // 创建内存 BIO 用于存储密钥
  BIO* bio_private = BIO_new(BIO_s_mem());
  BIO* bio_public = BIO_new(BIO_s_mem());

  // 将私钥写入 BIO(PKCS#8 格式)
  PEM_write_bio_RSAPrivateKey(bio_private, rsa, nullptr, nullptr, 0, nullptr,
    nullptr);

  // 将公钥写入 BIO(X.509 格式)
  PEM_write_bio_RSAPublicKey(bio_public, rsa);

  // 从 BIO 提取字符串
  char* priv_data = nullptr;
  char* pub_data = nullptr;
  long priv_len = BIO_get_mem_data(bio_private, &priv_data);
  long pub_len = BIO_get_mem_data(bio_public, &pub_data);

  private_key = std::string(priv_data, priv_len);
  public_key = std::string(pub_data, pub_len);

  // 释放资源
  BIO_free_all(bio_private);
  BIO_free_all(bio_public);
  RSA_free(rsa);
  BN_free(bn);
}

RSA 公钥加密

// 公钥加密
std::string EncryptWithPublic(const std::string& plaintext,
  const std::string& public_key) {
  BIO* bio = BIO_new_mem_buf(public_key.c_str(), -1);
  RSA* rsa = PEM_read_bio_RSAPublicKey(bio, nullptr, nullptr, nullptr);
  BIO_free_all(bio);

  if (!rsa) {
    return "";
  }

  int rsa_size = RSA_size(rsa);
  int max_plaintext_len =
    rsa_size - 42;  // RSA_PKCS1_OAEP_PADDING 填充后最大明文长度
  std::string encrypted_str;

  for (size_t i = 0; i < plaintext.length(); i += max_plaintext_len) {
    size_t len =
      std::min(max_plaintext_len, static_cast<int>(plaintext.length() - i));
    unsigned char* encrypted = new unsigned char[rsa_size];
    int result = RSA_public_encrypt(
      len, reinterpret_cast<const unsigned char*>(plaintext.c_str() + i),
      encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
    if (result == -1) {
      RSA_free(rsa);
      delete[] encrypted;
      return "";
    }
    encrypted_str.append(reinterpret_cast<char*>(encrypted), result);
    delete[] encrypted;
  }

  RSA_free(rsa);
  return encrypted_str;
}

RSA 私钥解密


// 私钥解密
std::string DecryptWithPrivate(const std::string& ciphertext,
  const std::string& private_key) {
  BIO* bio = BIO_new_mem_buf(private_key.c_str(), -1);
  RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr);
  BIO_free_all(bio);

  if (!rsa) {
    return "";
  }

  int rsa_size = RSA_size(rsa);
  std::string decrypted_str;

  for (size_t i = 0; i < ciphertext.length(); i += rsa_size) {
    unsigned char* decrypted = new unsigned char[rsa_size];
    int result = RSA_private_decrypt(
      rsa_size,
      reinterpret_cast<const unsigned char*>(ciphertext.c_str() + i),
      decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
    if (result == -1) {
      RSA_free(rsa);
      delete[] decrypted;
      return "";
    }
    decrypted_str.append(reinterpret_cast<char*>(decrypted), result);
    delete[] decrypted;
  }

  RSA_free(rsa);
  return decrypted_str;
}

生成ECDH 密钥对

#include <openssl/digest.h>
#include <openssl/ecdh.h>
#include <openssl/ec_key.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/sha.h>
#include <openssl/cipher.h>
#include <openssl/bio.h>
#include <openssl/md5.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
bool GenECDHKeypair(int nid,
                                std::string& public_key,
                                std::string& private_key) {
  bool ret = false;
  EC_KEY* ec_key = nullptr;
  unsigned char* pub_key_buf = nullptr;
  unsigned char* pri_key_buf = nullptr;
  do {
    ec_key = EC_KEY_new_by_curve_name(nid);
    if (!ec_key) {
      break;
    }

    EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);

    ret = EC_KEY_generate_key(ec_key);
    if (ret != 1) {
      break;
    }

    int pub_key_size = i2o_ECPublicKey(ec_key, &pub_key_buf);
    if (pub_key_size == 0 || !pub_key_buf) {
      break;
    }

    int pri_key_size = i2d_ECPrivateKey(ec_key, &pri_key_buf);
    if (pri_key_size == 0 || !pri_key_buf) {
      break;
    }
    
    public_key.assign((const char*)pub_key_buf, pub_key_size);
    private_key.assign((const char*)pri_key_buf, pri_key_size);

    ret = true;
  } while (false);

  if (ec_key) {
    EC_KEY_free(ec_key);
  }

  if (pub_key_buf) {
    OPENSSL_free(pub_key_buf);
  }

  if (pri_key_buf) {
    OPENSSL_free(pri_key_buf);
  }
  return ret;
}

生成ECDSA 密钥对


bool GenECDSAKeypair(int nid,
                                 std::string& public_key,
                                 std::string& private_key) {
  bool result = false;
  EC_KEY* ec_key = nullptr;
  BIO* bio = nullptr;
  do {
    ec_key = EC_KEY_new_by_curve_name(nid);
    if (!ec_key) {
      break;
    }

    EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);

    int ret = EC_KEY_generate_key(ec_key);
    if (ret != 1) {
      break;
    }

    ret = EC_KEY_check_key(ec_key);
    if (ret != 1) {
      break;
    }

    bio = BIO_new(BIO_s_mem());
    ret = PEM_write_bio_EC_PUBKEY(bio, ec_key);
    if (ret != 1 || BIO_flush(bio) != 1) {
      break;
    }
    char* ptr = nullptr;
    long size = BIO_get_mem_data(bio, &ptr);
    public_key.assign(ptr, size);
    BIO_free(bio);

    bio = BIO_new(BIO_s_mem());
    ret = PEM_write_bio_ECPrivateKey(bio, ec_key, nullptr, nullptr, 0, nullptr,
                                     nullptr);
    if (ret != 1 || BIO_flush(bio) != 1) {
      break;
    }
    ptr = nullptr;
    size = BIO_get_mem_data(bio, &ptr);
    private_key.assign(ptr, size);

    result = true;
  } while (false);

  if (nullptr != bio) {
    BIO_free(bio);
  }

  if (nullptr != ec_key) {
    EC_KEY_free(ec_key);
  }

  return result;
}

生成RSA 密钥对


bool GenRsaKeypair(std::string& public_key, std::string& private_key)
{
  // 产生RSA密钥
  RSA* rsa = RSA_new();
  BIGNUM* bn = BN_new();
  BN_set_word(bn, RSA_F4);
  RSA_generate_key_ex(rsa, 1024, bn, NULL);

  // 提取私钥
  BIO* bio_private = BIO_new(BIO_s_mem());
  PEM_write_bio_RSAPrivateKey(bio_private, rsa, NULL, NULL, 0, NULL, NULL);
  int private_key_len = BIO_pending(bio_private);
  char* pem_private_key = (char*)calloc(private_key_len + 1, 1);
  BIO_read(bio_private, pem_private_key, private_key_len);
  private_key.assign(pem_private_key, private_key_len);
  free(pem_private_key);
  BIO_free(bio_private);

  // 提取公钥
  BIO* bio_public = BIO_new(BIO_s_mem());
  PEM_write_bio_RSA_PUBKEY(bio_public, rsa);
  int public_key_len = BIO_pending(bio_public);
  char* pem_public_key = (char*)calloc(public_key_len + 1, 1);
  BIO_read(bio_public, pem_public_key, public_key_len);
  public_key.assign(pem_public_key, public_key_len);
  free(pem_public_key);
  BIO_free(bio_public);

  // 释放资源
  RSA_free(rsa);
  BN_free(bn);

  return true;
}

SHA256 ECDH 密钥协商

inline void* Sha256(const void* in,
                    size_t in_len,
                    void* out,
                    size_t* out_len) {
  *out_len = SHA256_DIGEST_LENGTH;
  return SHA256((const uint8_t*)in, in_len, (uint8_t*)out);
}

bool SHA256ECDH(int nid,
  const std::string& public_key,
  const std::string& private_key,
  std::string& result) {
  bool ret = false;
  EC_KEY* pub_ec_key = nullptr;
  EC_KEY* pri_ec_key = nullptr;

  do {
    pub_ec_key = EC_KEY_new_by_curve_name(nid);
    if (!pub_ec_key) {
      break;
    }
    auto uint8_pubkey = (const uint8_t*)public_key.data();
    pub_ec_key = o2i_ECPublicKey(&pub_ec_key, &uint8_pubkey, public_key.size());
    if (!pub_ec_key) {
      break;
    }

    pri_ec_key = EC_KEY_new_by_curve_name(nid);
    if (!pri_ec_key) {
      break;
    }

    auto uint8_privkey = (const uint8_t*)private_key.data();
    pri_ec_key = d2i_ECPrivateKey(&pri_ec_key, &uint8_privkey, private_key.size());
    if (!pri_ec_key) {
      break;
    }
   result.resize(SHA256_DIGEST_LENGTH);
   ECDH_compute_key(result.data(), SHA256_DIGEST_LENGTH,
   EC_KEY_get0_public_key(pub_ec_key), pri_ec_key, Sha256);
   
    ret = true;

  } while (false);

  // free memory
  if (pub_ec_key) {
    EC_KEY_free(pub_ec_key);
  }

  if (pri_ec_key) {
    EC_KEY_free(pri_ec_key);
  }
  return ret;
}

MD5 ECDH 密钥协商

inline void* MD5(const void* in,
  size_t in_len,
  void* out,
  size_t* out_len) {
  *out_len = MD5_DIGEST_LENGTH;
  MD5_CTX ctx;
  MD5_Init(&ctx);
  MD5_Update(&ctx, in, in_len);
  MD5_Final((uint8_t*)out, &ctx);
  return out;
}

bool MD5ECDH(int nid,
  const std::string& public_key,
  const std::string& private_key,
  std::string& result) {
  bool ret = false;
  EC_KEY* pub_ec_key = nullptr;
  EC_KEY* pri_ec_key = nullptr;

  do {
    pub_ec_key = EC_KEY_new_by_curve_name(nid);
    if (!pub_ec_key) {
      break;
    }
    auto uint8_pubkey = (const uint8_t*)public_key.data();
    pub_ec_key = o2i_ECPublicKey(&pub_ec_key, &uint8_pubkey, public_key.size());
    if (!pub_ec_key) {
      break;
    }

    pri_ec_key = EC_KEY_new_by_curve_name(nid);
    if (!pri_ec_key) {
      break;
    }

    auto uint8_privkey = (const uint8_t*)private_key.data();
    pri_ec_key = d2i_ECPrivateKey(&pri_ec_key, &uint8_privkey, private_key.size());
    if (!pri_ec_key) {
      break;
    }
 result.resize(MD5_DIGEST_LENGTH);
 ECDH_compute_key(result.data(), MD5_DIGEST_LENGTH,
   EC_KEY_get0_public_key(pub_ec_key), pri_ec_key, MD5);   
    ret = true;
  } while (false);

  // free memory
  if (pub_ec_key) {
    EC_KEY_free(pub_ec_key);
  }

  if (pri_ec_key) {
    EC_KEY_free(pri_ec_key);
  }
  return ret;
}

AES256GCM 加密


std::string Aes256GcmEncrypt(const void* once,
                                      int32_t once_len,
                                      const void* key,
                                      int32_t key_len,
                                      const void* aad,
                                      int32_t aad_len,
                                      const void* data,
                                      int32_t data_len,
                                      int tag_size,
                                      std::string& tag) {
  std::string result;
  EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
  EVP_CIPHER_CTX_init(ctx);
  EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
  do {
    // set iv size
    int ret =
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, once_len, nullptr);
    if (ret != 1) {
      break;
    }

    ret = EVP_EncryptInit_ex(ctx, nullptr, nullptr, (const uint8_t*)key,
                             (const uint8_t*)once);
    if (ret != 1) {
      break;
    }
    int out_len = 0;
    if (aad_len != 0) {
      ret = EVP_EncryptUpdate(ctx, nullptr, &out_len,
                              (const uint8_t*)aad, aad_len);
      if (ret != 1) {
        break;
      }
    }

    result.resize(EVP_CIPHER_CTX_block_size(ctx) + data_len);
    int encrypt_len = 0;
    if (data_len != 0) {
      ret = EVP_EncryptUpdate(ctx, (uint8_t*)result.data(), &out_len,
                              (const uint8_t*)data, data_len);
      if (ret != 1) {
        break;
      }

      encrypt_len = out_len;
    }

    ret = EVP_EncryptFinal_ex(ctx, (uint8_t*)result.data() + encrypt_len,
                              &out_len);
    if (ret != 1) {
      break;
    }

    encrypt_len += out_len;
    result.resize(encrypt_len);

    if (tag_size != 0) {
      tag.resize(tag_size);
      ret =
          EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag.data());
      if (ret != 1) {
        break;
      }
    }
  } while (false);
  EVP_CIPHER_CTX_free(ctx);
  return result;
}

AES256 GCM 解密


std::string AesGcmDecrypt(const void* once,
                                      int32_t once_len,
                                      const void* key,
                                      int32_t key_len,
                                      const void* aad,
                                      int32_t aad_len,
                                      const void* tag,
                                      int32_t tag_len,
                                      const void* data,
                                      int32_t data_len) {
  std::string result;
  EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
  EVP_CIPHER_CTX_init(ctx);
  
  EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
  do {
    int ret =
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, once_len, nullptr);
    if (ret != 1) {
      break;
    }

    ret = EVP_DecryptInit_ex(ctx, nullptr, nullptr, (const uint8_t*)key,
                             (const uint8_t*)once);
    if (ret != 1) {
      break;
    }
    int out_len = 0;
    // set aad
    if (aad_len != 0) {
      ret = EVP_DecryptUpdate(ctx, nullptr, &out_len,
                              (const uint8_t*)aad, aad_len);
      if (ret != 1) {
        break;
      }
    }
    result.resize(EVP_CIPHER_CTX_block_size(ctx) + data_len);
    int decrypt_len = 0;
    if (data_len != 0) {
      ret = EVP_DecryptUpdate(ctx, (uint8_t*)result.data(), &out_len,
                              (const uint8_t*)data, data_len);
      if (ret != 1) {
        break;
      }

      decrypt_len = out_len;
    }
    ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len,
                              (void*)tag);
    if (ret == 1) {
      ret = EVP_DecryptFinal_ex(ctx, (uint8_t*)result.data() + decrypt_len,
                                &out_len);
      if (ret == 1) {
        decrypt_len += out_len;
        result.resize(decrypt_len);
      } else {
        result.clear();
      }
    } else {
      result.clear();
    }
  } while (false);
  EVP_CIPHER_CTX_free(ctx);
  return result;
}

AES 加密


std::string AESEncrypt(const std::string& key,
  const void* data,
  int32_t data_len) {
  if ( 0 == data_len)
  {
    return "";
  }

  // 计算padding
  int padding = 16 - data_len % 16;
  std::string padding_data(data_len + padding, (char)padding);
  memcpy(padding_data.data(), data, data_len);

  uint8_t tmp_key[16] = {};
  uint8_t* ptmp_key = nullptr;
  if (key.length() == 16) {
    ptmp_key = (uint8_t*)key.data();
  }
  else {
    ptmp_key = tmp_key;
    memcpy(tmp_key, key.data(), key.length() > 16 ? 16 : key.length());
  }

  uint8_t iv[16] = {};
  memcpy(iv, ptmp_key, 16);

  std::string result(padding_data.size(), 0);
  AES_KEY aes_key;
  AES_set_encrypt_key(ptmp_key, 128, &aes_key);
  AES_cbc_encrypt((uint8_t*)padding_data.data(), (uint8_t*)result.data(),
    padding_data.length(), &aes_key, iv, AES_ENCRYPT);

  return result;
}

AES 解密


std::string AESDecrypt(const std::string& key, const void* data, int32_t len)
{
  if (key.empty() || len == 0) {
    return "";
  }

  uint8_t tmp_key[16] = {};
  uint8_t* ptmp_key = nullptr;
  if (key.length() == 16)
  {
    ptmp_key = (uint8_t*)key.data();
  }
  else
  {
    ptmp_key = tmp_key;
    memcpy(tmp_key, key.data(), key.length() > 16 ? 16 : key.length());
  }

  uint8_t iv[16] = {};
  memcpy(iv, ptmp_key, 16);


  std::string result(len, 0);
  AES_KEY aes_key;
  AES_set_decrypt_key(ptmp_key, 128, &aes_key);
  AES_cbc_encrypt((uint8_t*)data, (uint8_t*)result.data(), len,
    &aes_key, iv, AES_DECRYPT);
  // 去掉padding
  char padding = result[result.length() - 1];
  if (padding > 0 && padding <= 16)
  {
    result.resize(result.length() - padding);
  }
  return result;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mybatis配置文件解析(详细)

引言 在了解Mybatis如何帮助客户进行数据的存取后&#xff0c;便对Mybatis的配置文件起了兴趣&#xff0c;在查阅官方文档后&#xff0c;总结了平时能用到的配置&#xff0c;希望能对大家有帮助 1.核心配置文件 主要是指Mybatis-config.xml中 其包含了会深深影响Mybatis行为…

【BFS】《单源、多源 BFS:图搜索算法的双生力量》

文章目录 前言单源BFS例题一、迷宫中离入口最近的出口二、 最小基因变化三、单词接龙四、为高尔夫比赛砍树 多源BFS例题一、 01 矩阵二、飞地的数量三、地图中的最高点四、地图分析 结语 前言 什么是单源、多源BFS算法问题呢&#xff1f; BFS&#xff08;Breadth - First Sear…

【2025】基于springboot+vue的医院在线问诊系统设计与实现(源码、万字文档、图文修改、调试答疑)

基于Spring Boot Vue的医院在线问诊系统设计与实现功能结构图如下&#xff1a; 课题背景 随着互联网技术的飞速发展和人们生活水平的不断提高&#xff0c;传统医疗模式面临着诸多挑战&#xff0c;如患者就医排队时间长、医疗资源分配不均、医生工作压力大等。同时&#xff0c;…

STM32基础教程——PWM驱动舵机

目录 前言 技术实现 原理图 接线图 代码实现 内容要点 PWM基本结构 开启外设时钟 配置GPIO端口 配置时基单元 初始化输出比较单元 调整PWM占空比 输出比较通道重映射 舵机角度设置 实验结果 问题记录 前言 舵机&#xff08;Servo&#xff09;是一种位置&#xff…

odata 搜索帮助

参考如下链接&#xff1a; FIORI ELement list report 细节开发&#xff0c;设置过滤器&#xff0c;搜索帮助object page跳转等_fiori element label 变量-CSDN博客 注&#xff1a;odata搜索帮助可以直接将值带出来&#xff0c;而不需要进行任何的重定义 搜索帮助metedata配置…

Docker基本命令VS Code远程连接

Docker基本命令 创建自己的docker容器&#xff1a;docker run --net host --name Container_name --gpus all --shm-size 1t -it -v Your_Path:Your_Dir mllm:mac /bin/bashdocker run&#xff1a;用于创建并启动一个新容器-name&#xff1a;为当前新建的容器命名-gpus&#x…

大疆上云api直播功能如何实现

概述 流媒体服务器作为直播画面的中转站,它接收推流端的相机画面,同时拉流端找它获取相机的画面。整个流程如下: 在流媒体服务器上创建流媒体应用(app),一个流媒体服务器上面可以创建多个流媒体应用约定推拉流的地址。假设流媒体服务器工作在1935端口上面,假设创建的流…

理解文字识别:一文读懂OCR商业化产品的算法逻辑

文字识别是一项“历久弥新”的技术。早在上世纪初&#xff0c;工程师们就开始尝试使用当时有限的硬件设备扫描并识别微缩胶片、纸张上的字符。随着时代和技术的发展&#xff0c;人们在日常生活中使用的电子设备不断更新换代&#xff0c;文字识别的需求成为一项必备的技术基础&a…

使用 Cursor、MCP 和 Figma 实现工程化项目自动化,提升高达 200% 效率

直接上手不多说其他的&#xff01; 一、准备动作 1、Cursor下载安卓 1.1访问官方网站 打开您的网络浏览器&#xff0c;访问 Cursor 的官方网站&#xff1a;https://www.cursor.com/cn 1.2开始下载: 点击"Download for free" 根据您的浏览器设置&#xff0c;会自…

Arduino、ESP32驱动GUVA-S12SD UV紫外线传感器(光照传感器篇)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 UV紫外线传感器是一个测试紫外线总量的最佳传感器,它不需要使用波长滤波器,只对紫外线敏感。 Arduino UV紫外线传感器,直接输出对应紫外线指数(UV INDEX)的线性电压,输出电压范围大约0~1100mV(对应UV INDEX值…

PTA 1097-矩阵行平移

给定一个&#x1d45b;&#x1d45b;nn的整数矩阵。对任一给定的正整数&#x1d458;<&#x1d45b;k<n&#xff0c;我们将矩阵的奇数行的元素整体向右依次平移1、……、&#x1d458;、1、……、&#x1d458;、……1、……、k、1、……、k、……个位置&#xff0c;平移…

Notepad++ 替换 换行符 为 逗号

多行转一行&#xff0c;逗号分隔 SPO2025032575773 SPO2025032575772 SPO2025032575771 SPO2025032575771 SPO2025032575770为了方便快速替换&#xff0c;我们需要先知道这样类型的数据都存在哪些换行符。 点击【视图】-【显示符号】-【显示行尾符】 对于显示的行尾换行符【C…

使用飞书API自动化更新共享表格数据

飞书API开发之自动更新共享表格 天马行空需求需求拆解1、网站数据爬取2、飞书API调用2.1 开发流程2.2 创建应用2.3 配置应用2.4 发布应用2.5 修改表格权限2.6 获取tenant_access_token2.7 调用API插入数据 总结 天马行空 之前一直都是更新的爬虫逆向内容&#xff0c;工作中基本…

使用vscode搭建pywebview集成vue项目示例

文章目录 前言环境准备项目源码下载一、项目说明1 目录结构2 前端项目3 后端项目获取python安装包(选择对应版本及系统) 三、调试与生成可执行文件1 本地调试2 打包应用 四、核心代码说明1、package.json2、vite.config.ts设置3、main.py后端入口文件说明 参考文档 前言 本节我…

蓝桥杯嵌入式十六届模拟三

由硬件框图可以知道我们要配置LED 和按键 一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.…

onedav一为导航批量自动化导入网址(完整教程)

OneNav作为一个功能强大的导航工具,支持后台管理、加密链接、浏览器书签批量导入等功能,能够帮助用户轻松打造专属的导航页面。今天,我将为大家详细介绍如何实现OneNav导航站的批量自动化导入网址。 1、建立要批量导入的表格 格局需要创建表格,表格的要求是一定要有需要,…

Linux之编辑器vim命令

vi/vim命令&#xff1a; 终端下编辑文件的首选工具&#xff0c;号称编辑器之神 基本上分为三种模式&#xff0c;分别是 命令模式&#xff08;command mode&#xff09;>输入vi的命令和快捷键&#xff0c;默认打开文件的时候的模式插入模式&#xff08;insert mode&#x…

备赛蓝桥杯之第十六届模拟赛2期职业院校组第四题:地址识别

提示&#xff1a;本篇文章仅仅是作者自己目前在备赛蓝桥杯中&#xff0c;自己学习与刷题的学习笔记&#xff0c;写的不好&#xff0c;欢迎大家批评与建议 由于个别题目代码量与题目量偏大&#xff0c;请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题&#xff0…

多模态自动驾驶混合渲染HRMAD:将NeRF和3DGS进行感知验证和端到端AD测试

基于3DGS和NeRF的三维重建技术在过去的一年中取得了快速的进步&#xff0c;动态模型也变得越来越普遍&#xff0c;然而这些模型仅限于处理原始轨迹域内的对象。 HRMAD作为一种混合方案&#xff0c;将传统的基于网格的动态三维神经重建和物理渲染优势结合&#xff0c;支持在任意…

mac m3 pro 部署 stable diffusion webui

什么是Stable Diffusion WebUI &#xff1f; Stable Diffusion WebUI 是一个基于Stable Diffusion模型开发的图形用户界面&#xff08;GUI&#xff09;工具。通过这个工具&#xff0c;我们可以很方便的基于提示词&#xff0c;描述一段文本来指导模型生成相应的图像。相比较通过…