OpenSSL 使用AES对文件加解密

AES(Advanced Encryption Standard)是一种对称加密算法,它是目前广泛使用的加密算法之一。AES算法是由美国国家标准与技术研究院(NIST)于2001年发布的,它取代了原先的DES(Data Encryption Standard)算法,成为新的标准。AES是一种对称加密算法,意味着加密和解密使用相同的密钥。这就要求密钥的安全性非常重要,因为任何拥有密钥的人都能进行加密和解密操作。其密钥长度,包括128位、192位和256位。不同长度的密钥提供了不同级别的安全性,通常更长的密钥长度意味着更高的安全性。

该算法支持多种工作模式,其中两种常见的模式是CBC(Cipher Block Chaining)和ECB(Electronic Codebook)。

  1. CBC 模式(Cipher Block Chaining):
    • 工作原理:
      • CBC模式对每个明文块进行加密前,先与前一个密文块进行异或操作。首个块使用一个初始化向量(IV)与明文异或。这种链式反馈机制使得每个密文块的加密都依赖于前一个块的密文,从而增加了安全性。
    • 特点:
      • 带有初始化向量,对同样的明文块加密得到的密文块会随着其前面的明文块的不同而不同。
      • 适用于加密长度超过一个块的数据。
    • 优点和缺点:
      • 优点:提供更高的安全性,适用于加密大块的数据。
      • 缺点:由于加密是依赖于前一个块的密文,所以无法进行并行加密处理。
  2. ECB 模式(Electronic Codebook):
    • 工作原理:
      • ECB模式将明文分割成块,每个块独立加密,然后再组合成密文。相同的明文块将始终加密为相同的密文块。
    • 特点:
      • 不需要初始化向量,同样的明文会得到同样的密文。
      • 适用于加密独立的数据块,但对于相同的块,ECB模式下的输出相同。
    • 优点和缺点:
      • 优点:简单,易于实现。
      • 缺点:相同的明文块生成相同的密文块,可能导致安全性问题。不适用于加密大块的数据。

在选择模式时,需要根据具体的应用场景和需求权衡安全性和性能。一般来说,CBC模式是更安全的选择,而ECB模式可能更容易实现和理解。在实际应用中,还可以考虑其他模式,如CTR(Counter)模式和GCM(Galois/Counter Mode)模式等,这些模式结合了安全性和性能的考虑。

本次案例中所需要使用的头文件信息如下所示;

#define  _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>

extern "C"
{
#include <openssl/applink.c>
}

#pragma comment(lib,"libssl_static.lib")
#pragma comment(lib,"libcrypto.lib")

使用CBC模式加解密

Cipher Block Chaining (CBC) 模式是一种对称加密的分组密码工作模式。在 CBC 模式中,明文被分成固定大小的块,并使用加密算法逐个处理这些块。每个块都与前一个块的密文进行异或运算,然后再进行加密。这个过程导致了一种“链接”效果,因此得名 Cipher Block Chaining。

以下是 CBC 模式的详细概述:

初始向量 (Initialization Vector, IV)

  • 在 CBC 模式中,每个消息的第一个块使用一个初始向量 (IV)。IV 是一个固定长度的随机数,它在每次加密不同消息时都应该是唯一的。IV 的作用是在每个块的加密中引入随机性,以防止相同的明文块生成相同的密文块。

分组加密

  • 消息被分成固定大小的块(通常为 64 比特或 128 比特),然后每个块都被分组加密。最常用的块加密算法是 AES。

异或运算

  • 在每个块加密之前,明文块与前一个密文块进行异或运算。这就是“链接”发生的地方。第一个块与 IV 异或。

加密

  • 异或运算后的结果被送入块加密算法进行加密。得到的密文块成为下一个块的 IV。

解密

  • 在解密时,密文块被送入块解密算法进行解密。解密后的结果与前一个密文块进行异或运算,得到明文块。

模式串行化

  • CBC 模式是串行的,因为每个块的加密都依赖于前一个块的密文。这也意味着无法并行处理整个消息。

填充

  • 如果明文的长度不是块大小的整数倍,需要进行填充。常见的填充方案有 PKCS#7 填充。

安全性

  • 当使用 CBC 模式时,密文块的顺序对安全性至关重要。如果消息的两个块对调,解密后会得到不同的明文。因此,必须保证密文块的顺序不被篡改。

使用场景

  • CBC 模式常用于保护传输层安全协议(如 TLS)中,以提供加密和数据完整性。

总体而言,CBC 模式提供了一种相对强大的加密方法,但在实现时需要注意使用随机且不可预测的 IV 以及处理填充的问题。

AES_set_encrypt_key 函数。具体来说,它用于将原始密钥设置为可以在 AES 加密算法中使用的格式。以下是该函数的原型:

int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  • userKey:指向用于设置密钥的输入数据的指针,即原始密钥。
  • bits:密钥长度,以比特为单位。在使用 AES 加密算法时,通常为 128、192 或 256。
  • key:指向 AES_KEY 结构的指针,用于存储设置后的密钥信息。

该函数返回值为零表示成功,非零表示失败。成功调用后,key 参数中存储了经过格式化的密钥信息,可以在后续的 AES 加密操作中使用。

AES_cbc_encrypt 是 OpenSSL 库中用于执行 AES 算法中的 Cipher Block Chaining (CBC) 模式的函数。在 CBC 模式中,每个明文块在加密之前会与前一个密文块进行异或运算,以增加密码的随机性。

以下是 AES_cbc_encrypt 函数的原型:

void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, const int enc);
  • in:指向输入数据(明文)的指针。
  • out:指向输出数据(密文)的指针。
  • length:数据的长度,以字节为单位。
  • key:指向 AES_KEY 结构的指针,其中包含了加密密钥。
  • ivec:Initialization Vector(IV),用于增强密码的随机性,也是前一个密文块。在 CBC 模式中,IV 对于第一个数据块是必需的,之后的 IV 由前一个密文块决定。
  • enc:指定操作是加密(AES_ENCRYPT)还是解密(AES_DECRYPT)。

AES_set_decrypt_key 函数。该函数用于将加密时使用的密钥调整为解密时使用的密钥,以便进行解密操作。

以下是 AES_set_decrypt_key 函数的原型:

int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  • userKey:指向用于设置解密密钥的输入密钥数据的指针。
  • bits:密钥长度,以比特为单位。支持的长度包括 128、192 和 256 比特。
  • key:指向 AES_KEY 结构的指针,该结构将存储设置后的解密密钥。

实现加解密功能,如下openssl_aes_cbc_encrypt用于使用CBC模式加密数据,openssl_aes_cbc_decrypt则相反用于解密数据。

// 初始化密钥
const unsigned char key[AES_BLOCK_SIZE] = { 0x12,0x55,0x64,0x69,0xf1 };

// 初始化向量
unsigned char iv[AES_BLOCK_SIZE] = { 0 };

// AES CBC 模式加密
// 参数:
// - in: 待加密的数据
// - len: 待加密数据的长度
// - out: 存放加密结果的缓冲区
// 返回值:
// - 返回填充后加密数据的长度,失败返回-1
int openssl_aes_cbc_encrypt(char* in, size_t len, char* out)
{
	AES_KEY aes;

	// 填充数据为AES_BLOCK_SIZE的整数倍
	char* aesIn;
	int blockNum, aesInLen;

	// 设置加密密钥
	if (AES_set_encrypt_key(key, 128, &aes) < 0)
	{
		return -1;
	}

	// 判断原始数据长度是否AES_BLOCK_SIZE的整数倍
	if ((len % AES_BLOCK_SIZE) != 0)
	{
		// 不是整数倍则用0填充
		blockNum = len / AES_BLOCK_SIZE + 1;
		aesInLen = blockNum * AES_BLOCK_SIZE;
		aesIn = (char*)calloc(aesInLen, 1);
		memcpy(aesIn, in, len);
	}
	else
	{
		aesInLen = len;
		aesIn = (char*)calloc(aesInLen, 1);
		memcpy(aesIn, in, len);
	}

	// AES CBC 模式加密
	AES_cbc_encrypt((unsigned char*)aesIn, (unsigned char*)out, aesInLen, &aes, iv, AES_ENCRYPT);

	// 释放分配的内存
	free(aesIn);

	// 返回填充后加密数据的长度
	return aesInLen;
}

// AES CBC 模式解密
// 参数:
// - in: 待解密的数据
// - len: 待解密数据的长度
// - out: 存放解密结果的缓冲区
// 返回值:
// - 成功返回0,失败返回-1
int openssl_aes_cbc_decrypt(char* in, size_t len, char* out)
{
	AES_KEY aes;
	
	// 设置解密密钥
	if (AES_set_decrypt_key(key, 128, &aes) < 0)
	{
		return -1;
	}

	// AES CBC 模式解密
	AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT);

	// 返回成功
	return 0;
}

当需要对数据加密时,首先打开被加密文件这里我们打开的时csdn.zip文件,加密后会写出为csdn.cbc文件;

int main(int argc, char* argv[])
{
	// 存放填充字节数的数组
	char offset[4] = { '0' };

	char* src = nullptr, *dst = nullptr;
	int inlen, outlen, size;
	FILE* srcFile, *dstFile;

	// 打开被加密源文件
	srcFile = fopen("d://comp/csdn.zip", "rb");

	// 加密后写出文件
	dstFile = fopen("d://comp/csdn.cbc", "wb+");

	// 获取文件大小
	fseek(srcFile, 0, SEEK_END);
	inlen = ftell(srcFile);
	if (inlen < 0)
	{
		return 0;
	}
	fseek(srcFile, 0, SEEK_SET);

	// -------------------------------------------------------
	// 开始加密
	src = (char*)calloc(inlen, 1);
	size = fread(src, 1, inlen, srcFile);
	std::cout << "读入字节: " << size << std::endl;

	// 输出变量申请的空间额外增加16字节
	outlen = (inlen / 16 + 1) * 16;
	dst = (char*)calloc(outlen, 1);

	// 调用加密函数
	size = openssl_aes_cbc_encrypt(src, inlen, dst);

	// 获取填充的字节数,记录到输出文件的前4个字节内
	sprintf(offset, "%d", size - inlen);
	fwrite(offset, sizeof(char), 4, dstFile);

	// -------------------------------------------------------
	// 输出加密后的文件或者解密后的文件,文件大小应与原始文件一致
	size = fwrite(dst, 1, size, dstFile);
	std::cout << "输出文件大小: " << size << std::endl;

	fcloseall();
	free(src);
	free(dst);
	system("pause");
	return 0;
}

运行后输出效果图如下所示;
在这里插入图片描述

解密时同样需要打开文件,将加密文件csdn.cbc打开,并解密输出成csdnde.zip文件;

int main(int argc, char* argv[])
{
	// 存放填充字节数的数组
	char offset[4] = { '0' };

	char* src = nullptr, *dst = nullptr;
	int inlen, outlen, size;
	FILE* srcFile, *dstFile;

	// 打开加密后的文件
	srcFile = fopen("d://comp/csdn.cbc", "rb");

	// 解密后写出的文件
	dstFile = fopen("d://comp/csdnde.zip", "wb+");

	// 获取文件大小
	fseek(srcFile, 0, SEEK_END);
	inlen = ftell(srcFile);
	if (inlen < 0)
	{
		return 0;
	}
	fseek(srcFile, 0, SEEK_SET);

	// -------------------------------------------------------
	fread(offset, sizeof(char), 4, srcFile);
	inlen -= 4;
	src = (char*)calloc(inlen, 1);

	// 从加密后的文件中获取填充的字节数
	size = fread(src, 1, inlen, srcFile);
	std::cout << "读入字节: " << size << std::endl;

	// 得到原始文件的大小
	size = size - atoi(offset);

	outlen = (inlen / 16 + 1) * 16;
	dst = (char*)calloc(outlen, 1);

	// 解密
	openssl_aes_cbc_decrypt(src, inlen, dst);

	// -------------------------------------------------------

	// 输出加密后的文件或者解密后的文件,文件大小应与原始文件一致
	size = fwrite(dst, 1, size, dstFile);
	std::cout << "输出文件大小: " << size << std::endl;

	fcloseall();
	free(src);
	free(dst);
	system("pause");
	return 0;
}

运行后输出效果图如下所示;

在这里插入图片描述

使用ECB模式加解密

Electronic Codebook (ECB) 模式是一种对称加密的分组密码工作模式。在 ECB 模式中,每个明文块都被独立加密,不受其他块的影响。这意味着相同的明文块将始终生成相同的密文块,这可能导致一些安全性问题。

以下是 ECB 模式的详细概述:

分组加密

  • 消息被分成固定大小的块(通常为 64 比特或 128 比特),然后每个块都被独立加密。最常用的块加密算法是 AES。

无链接

  • 在 ECB 模式中,每个块的加密是独立的,不会受到前一个或后一个块的影响。这意味着相同的明文块将生成相同的密文块。

模式串行化

  • ECB 模式允许对整个消息进行并行处理,因为每个块都是独立加密的。这是与 CBC 模式相比的一个优势,因为它允许更高效的实现。

填充

  • 如果明文的长度不是块大小的整数倍,需要进行填充。常见的填充方案有 PKCS#7 填充。

安全性问题

  • 主要的安全性问题在于相同的明文块生成相同的密文块,这可能导致一些攻击。例如,如果两个块的内容相同,那么它们的密文也将相同。

使用场景

  • 由于安全性问题,ECB 模式并不适合所有场景。一般来说,ECB 模式主要用于对称加密算法的基本理解和学术研究,而在实际应用中更常使用其他工作模式,如 CBC 或 GCM。

总体而言,ECB 模式是一种简单的分组密码工作模式,但由于安全性问题,实际应用中更常使用其他工作模式。

AES_ecb_encrypt 是 OpenSSL 库中用于执行 AES 算法的 ECB 模式加密的函数。下面是对该函数的详细概述:

int AES_ecb_encrypt(const unsigned char *input, unsigned char *output, const AES_KEY *key, const int enc);

参数说明:

  • input: 要加密的数据的输入缓冲区的指针。
  • output: 加密后的数据的输出缓冲区的指针。
  • key: AES 密钥的结构体指针,其中包含了加密所需的密钥信息。
  • enc: 一个整数值,用于指定是执行加密(AES_ENCRYPT)还是解密(AES_DECRYPT)操作。

返回值:

  • 返回 0 表示成功,其他值表示错误。

功能说明:

  • AES_ecb_encrypt 函数用于在 ECB 模式下执行 AES 算法的加密或解密操作,具体取决于 enc 参数。
  • 在 ECB 模式下,该函数将输入的数据块独立地加密(或解密),每个块的输出结果不受前后块的影响。
  • 函数通过 key 参数提供的密钥信息执行加密或解密操作。

AES_ecb_encrypt 是 OpenSSL 库中用于执行 AES 算法的 ECB 模式加密或解密的函数。下面是对该函数的详细概述:

int AES_ecb_encrypt(const unsigned char *input, unsigned char *output, const AES_KEY *key, const int enc);

参数说明:

  • input: 要加密或解密的数据块的输入缓冲区指针。
  • output: 加密或解密后的数据块的输出缓冲区指针。
  • key: AES 密钥的结构体指针,包含了加密或解密所需的密钥信息。
  • enc: 一个整数值,用于指定是执行加密(AES_ENCRYPT)还是解密(AES_DECRYPT)操作。

返回值:

  • 返回 0 表示成功,其他值表示错误。

功能说明:

  • AES_ecb_encrypt 函数用于在 ECB 模式下执行 AES 算法的加密或解密操作,具体取决于 enc 参数。
  • 在 ECB 模式下,该函数将输入的数据块独立地加密(或解密),每个块的输出结果不受前后块的影响。
  • 函数通过 key 参数提供的密钥信息执行加密或解密操作。
// AES ECB 模式加密
// 参数:
// - in: 待加密的数据
// - len: 待加密数据的长度
// - out: 存放加密结果的缓冲区
// 返回值:
// - 成功返回填充后加密数据的长度,失败返回-1
int openssl_aes_ecb_enrypt(char* in, size_t len, char* out)
{
	int i;
	int blockNum;
	int aesInLen;
	char* aesIn;
	AES_KEY aes;

	// 设置加密密钥
	if (AES_set_encrypt_key(key, 128, &aes) < 0)
		return -1;
	// 判断原始数据长度是否AES_BLOCK_SIZE的整数倍
	if ((len % AES_BLOCK_SIZE) != 0)
	{
		blockNum = len / AES_BLOCK_SIZE + 1;
		aesInLen = blockNum * AES_BLOCK_SIZE;
		aesIn = (char*)calloc(aesInLen, 1);
		memcpy(aesIn, in, len);
	}
	else
	{
		blockNum = len / AES_BLOCK_SIZE;
		aesInLen = len;
		aesIn = (char*)calloc(aesInLen, 1);
		memcpy(aesIn, in, len);
	}

	// 由于ECB每次只处理AES_BLOCK_SIZE大小的数据,所以通过循环完成所有数据的加密
	for (i = 0; i < blockNum; i++)
	{
		AES_ecb_encrypt((unsigned char*)aesIn, (unsigned char*)out, &aes, AES_ENCRYPT);
		aesIn += AES_BLOCK_SIZE;
		out += AES_BLOCK_SIZE;
	}

	// 释放内存
	// free(aesIn);
	// 返回填充后加密数据的长度
	return aesInLen;
}

// AES ECB 模式解密
// 参数:
// - in: 待解密的数据
// - len: 待解密数据的长度
// - out: 存放解密结果的缓冲区
// 返回值:
// - 成功返回0,失败返回-1
int openssl_aes_ecb_decrypt(char* in, size_t len, char* out)
{
	unsigned int i;
	AES_KEY aes;
	// 设置解密密钥
	if (AES_set_decrypt_key(key, 128, &aes) < 0)
	{
		return -1;
	}
	// 循环解密每个数据块
	for (i = 0; i < len / AES_BLOCK_SIZE; i++)
	{
		AES_ecb_encrypt((unsigned char*)in, (unsigned char*)out, &aes, AES_DECRYPT);
		in += AES_BLOCK_SIZE;
		out += AES_BLOCK_SIZE;
	}
	// 返回成功
	return 0;
}

当需要对数据加密时,首先打开被加密文件这里我们打开的时csdn.zip文件,加密后会写出为csdn.ecb文件;

int main(int argc, char* argv[])
{
	// 存放填充字节数的数组
	char offset[4] = { '0' };

	char* src = nullptr, *dst = nullptr;
	int inlen, outlen, size;
	FILE* srcFile, *dstFile;

	// 打开被加密源文件
	srcFile = fopen("d://comp/csdn.zip", "rb");

	// 加密后写出文件
	dstFile = fopen("d://comp/csdn.ecb", "wb+");

	// 获取文件大小
	fseek(srcFile, 0, SEEK_END);
	inlen = ftell(srcFile);
	if (inlen < 0)
	{
		return 0;
	}
	fseek(srcFile, 0, SEEK_SET);

	// -------------------------------------------------------
	// 开始加密
	src = (char*)calloc(inlen, 1);
	size = fread(src, 1, inlen, srcFile);
	std::cout << "读入字节: " << size << std::endl;

	// 输出变量申请的空间额外增加16字节
	outlen = (inlen / 16 + 1) * 16;
	dst = (char*)calloc(outlen, 1);

	// ECB加密
	size = openssl_aes_ecb_enrypt(src, inlen, dst);
	sprintf(offset, "%d", size - inlen);
	fwrite(offset, sizeof(char), 4, dstFile);

	// -------------------------------------------------------
	// 输出加密后的文件或者解密后的文件,文件大小应与原始文件一致
	size = fwrite(dst, 1, size, dstFile);
	std::cout << "输出文件大小: " << size << std::endl;

	fcloseall();
	free(src);
	free(dst);
	system("pause");
	return 0;
}

运行后输出效果图如下所示;

在这里插入图片描述

解密时同样需要打开文件,将加密文件csdn.ecb打开,并解密输出成csdnde.zip文件;

int main(int argc, char* argv[])
{
	// 存放填充字节数的数组
	char offset[4] = { '0' };

	char* src = nullptr, *dst = nullptr;
	int inlen, outlen, size;
	FILE* srcFile, *dstFile;

	// 打开加密后的文件
	srcFile = fopen("d://comp/csdn.ecb", "rb");

	// 解密后写出的文件
	dstFile = fopen("d://comp/csdnde.zip", "wb+");

	// 获取文件大小
	fseek(srcFile, 0, SEEK_END);
	inlen = ftell(srcFile);
	if (inlen < 0)
	{
		return 0;
	}
	fseek(srcFile, 0, SEEK_SET);

	// -------------------------------------------------------
	fread(offset, sizeof(char), 4, srcFile);
	inlen -= 4;
	src = (char*)calloc(inlen, 1);

	// 从加密后的文件中获取填充的字节数
	size = fread(src, 1, inlen, srcFile);
	std::cout << "读入字节: " << size << std::endl;

	// 得到原始文件的大小
	size = size - atoi(offset);

	outlen = (inlen / 16 + 1) * 16;
	dst = (char*)calloc(outlen, 1);

	// 解密
	openssl_aes_ecb_decrypt(src, inlen, dst);

	// -------------------------------------------------------

	// 输出加密后的文件或者解密后的文件,文件大小应与原始文件一致
	size = fwrite(dst, 1, size, dstFile);
	std::cout << "输出文件大小: " << size << std::endl;

	fcloseall();
	free(src);
	free(dst);
	system("pause");
	return 0;
}

运行后输出效果图如下所示;

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sed命令

目录 一、sed 1.sed命令选项 2.语法选项 3.sed脚本格式 4.搜索替代 5.分组后向引用 1.提取版本号&#xff1a; 2.提取IP地址 3.提取数字权限 6.变量 二、免交互 1.多行重定向 2.免交互脚本 总结&#xff1a;本章主要介绍了seq和免交互的用法及相关知识 一、sed s…

p9 第55题 两个有序单链表L1,L2求交的操作,得到新的链表L3,L3任然保持有序的状态 中国计量大学2016年数据结构题(c语言代码实现)

本题代码如下 linklist merge(linklist* L1, linklist* L2)//将两个链表的公共元素合并产生新链表 {lnode* ra (*L1)->next, * rb (*L2)->next;lnode* r;lnode* s;lnode* C (lnode*)malloc(sizeof(lnode));C->next NULL;r C;while (ra && rb)//循环跳出…

泛微 E-Office sample权限绕过+文件上传组合漏洞Getshell

0x01 产品简介 泛微E-Office是一款标准化的协同 OA 办公软件&#xff0c;泛微协同办公产品系列成员之一,实行通用化产品设计&#xff0c;充分贴合企业管理需求&#xff0c;本着简洁易用、高效智能的原则&#xff0c;为企业快速打造移动化、无纸化、数字化的办公平台。 0x02 漏…

lv11 嵌入式开发 WDT实验 12

目录 1 WDT简介 2 Exynos4412下的WDT控制器 2.1 概述 2.2 WDT的特性 2.3 工作原理 2.4 其他细节 3 WDT寄存器详解 3.1 WTCON控制寄存器 3.2 WTDAT 实时中断寄存器 3.3 WTCNT 递减计数器 3.4 WTCLRINT清除中断寄存器 4 WDT编程 1 WDT简介 Watch Dog Timer即看门狗定…

探索三种生成模型:基于DDPMs、NCSNs和SDEs方法的Diffusion

探索三种生成模型&#xff1a;基于DDPMs、NCSNs和SDEs方法的Diffusion 去噪扩散概率模型&#xff08;DDPMs&#xff09;正向过程反向过程 噪声条件得分网络&#xff08;NCSNs&#xff09;正向过程初始化训练 NCSNs生成样本 反向过程 随机微分方程&#xff08;SDEs&#xff09;原…

自然资源科普交互大屏助力自然资源的保护

在当代社会&#xff0c;自然资源的科学管理和可持续利用变得愈发重要。为了提高公众对于自然资源的认知和理解&#xff0c;科普交互大屏成为一个新兴的工具。它通过生动的图像和实时数据展示&#xff0c;以及与观众的互动方式&#xff0c;让人们更深入地了解自然资源和环境保护…

eNSP防火墙USG6000V使用Web界面登入教程

文章目录 登入流程1、下载USG6000V的镜像包2、导入USG6000V的镜像包3、配置防火墙web页面4、修改本机vmnet1网卡的ipv4地址5、在eNSP上添加云6、配置防火墙管理地址&#xff0c;开启http服务7、关闭电脑防火墙8、访问web页面 登入流程 1、下载USG6000V的镜像包 链接&#xff…

数据库应用:MongoDB 库与集合管理

目录 一、理论 1.MongoDB用户管理 2.MogoDB库管理 3.MogoDB集合管理 二、实验 1.MongoDB用户管理 2.MogoDB库管理 3.MogoDB集合管理 三、问题 1.不显示新创建的数据库 2.插入数据报错 3.删除指定数据库报错 一、理论 1.MongoDB用户管理 (1) 内置角色 数据库用户…

Postman进阶功能实战演练

Postman除了前面介绍的一些功能&#xff0c;还有其他一些小功能在日常接口测试或许用得上。今天&#xff0c;我们就来盘点一下&#xff0c;如下所示&#xff1a; 1.数据驱动 想要批量执行接口用例&#xff0c;我们一般会将对应的接口用例放在同一个Collection中&#xff0c;然…

ZYNQ_project:IIC_EEPROM

EEPROM简介&#xff1a; EEPROM(Electrically Erasable Progammable Read Only Memory&#xff0c; E2PROM)是指带电可擦可编程只读存 储器&#xff0c;是一种常用的非易失性存储器&#xff08;掉电数据不丢失&#xff09;&#xff0c; E2PROM 有多种类型的产品&#xff0c;我…

【计算机网络学习之路】序列化,反序列化和初识协议

文章目录 前言一. 序列化和反序列化1.自己实现2. JSON 二. 初识协议结束语 前言 本系列文章是计算机网络学习的笔记&#xff0c;欢迎大佬们阅读&#xff0c;纠错&#xff0c;分享相关知识。希望可以与你共同进步。 本篇博文讲解应用层的序列化和反序列化&#xff0c;还有见一…

Linux基础项目开发1:量产工具——显示系统(二)

前言&#xff1a; 前面我们已经对这个项目的基本框架有了一个初步的了解与认识&#xff0c;要实现显示管理器与输入管理器&#xff0c;有输入有输出基本就实现这个项目的大部分功能了&#xff0c;首先我们先来做显示系统&#xff0c;对于上层系统为了让程序更好扩展&#xff0c…

Python分享之字符串格式化 (%操作符)

在许多编程语言中都包含有格式化字符串的功能&#xff0c;比如C和Fortran语言中的格式化输入输出。Python中内置有对字符串进行格式化的操作%。 模板 格式化字符串时&#xff0c;Python使用一个字符串作为模板。模板中有格式符&#xff0c;这些格式符为真实值预留位置&#xff…

【Android Jetpack】Hilt 依赖注入框架

文章目录 依赖注入DaggerHiltKoin添加依赖项Hilt常用注解的含义HiltAndroidAppAndroidEntryPointInjectModuleInstallInProvidesEntryPoint Hilt组件生命周期和作用域如何使用 Hilt 进行依赖注入 依赖注入 依赖注入是一种软件设计模式&#xff0c;它允许客户端从外部源获取其依…

计算机丢失vcomp140.dll是什么意思,如何解决与修复(附教程)

vcomp140.dll缺失的5种解决方法以及vcomp140.dll缺失原因 引言&#xff1a; 在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp140.dll缺失”。这个错误提示通常出现在运行某些程序或游戏时&#xff0c;给使用者带来了困扰。本文…

【蓝桥杯 LCA 差分】 砍树

题目分析&#xff1a; 这道题还是比较裸的一道书上差分的题目了 对于每一对标记点(x,y) 他们之间的路径就是 x − > L C A ( x , y ) − > y x->LCA(x,y)->y x−>LCA(x,y)−>y 这条路径上的每一条边都要经过。 那么对于一条边&#xff0c;什么时候砍掉这条…

【推荐系统】MMOE笔记 20231126

paper阅读 任务差异带来的固有冲突实际上会损害至少某些任务的预测&#xff0c;特别是当模型参数在所有任务之间广泛共享时。&#xff08;在说ESMM&#xff09; 共享底层参数可以减少过拟合风险&#xff0c;但是会遇到任务差异引起的优化冲突&#xff0c;因为所有任务都需要在…

Django二转Day02

http #1 http 是什么#2 http特点#3 请求协议详情 -请求首行---》请求方式&#xff0c;请求地址&#xff0c;请求协议版本 -请求头---》key:value形式 -referer&#xff1a;上一次访问的地址 -user-agenet&#xff1a;客户端类型 -name&#x…

JSP迭代标签之 forEach循环标签 基本使用讲解

好 之前我们讲完了 我们的条件动作标签 那么 我们来继续说 迭代标签 所谓迭代就是 将某个主体循环多次 也可以循环 集合 对象 map 这个标签叫 forEach items 就是 我们要循环的数据 注意 这里 操作的也是域对象中的值 begin 开始说 例如 i 0;i<x;i begin 就是开始数 当前…

1.Spring源码解析-ClassPathXmlApplicationContext

此类是读取spring的xml配置文件并解析。也是源码入口之一。 我们调试即将开始。 传递给父类设置值 经调试我们得到是给AbstractApplicationContext设置默认的应用上下文父级的值&#xff0c;很明显是空 给父类AbstractRefreshableConfigApplicationContext设置属性 刷新容器…
最新文章