openssl AF_ALG引擎使用

cmd

AF_ALG是Linux提供的一种虚拟接口,用于访问内核中的加密算法。在Linux中,可以使用AF_ALG接口配合加密算法框架(Crypto API)来进行加密操作。

以下是一个使用AF_ALG和openssl进行加密操作的例子:

# 加密
openssl engine -t afalg -k afalg -c
 
# 加载AF_ALG引擎
openssl engine afalg
 
# 设置会话使用的加密算法和密钥
openssl ciphers -v 'aes-128-cbc'
 
# 加密文件
openssl enc -engine afalg -aes-128-cbc -in input.txt -out output.txt -pass pass:YOUR_PASSWORD

在这个例子中,我们首先加载AF_ALG加密引擎。然后,我们设置会话使用的加密算法为AES-128-CBC。最后,我们使用openssl的enc命令进行加密操作,指定输入文件input.txt和输出文件output.txt,并使用密钥mysecretkey进行加密。

注意:在使用AF_ALG引擎之前,你需要确保系统中已经安装了libafalg-dev包,并且你的内核支持AF_ALG。

这只是一个基本的示例,实际使用时可能需要根据具体的加密算法和系统配置进行调整。

测试实例:(这是在101编译服务器环境上测试的)

der@somewhere:~/tmp/tmp$ openssl engine -t afalg -k afalg -c
engine: Cannot mix flags and engine names.
engine: Use -help for summary.
der@somewhere:~/tmp/tmp$ openssl engine -t afalg -k afalg
engine: Cannot mix flags and engine names.
engine: Use -help for summary.
der@somewhere:~/tmp/tmp$ openssl engine -t afalg
(afalg) AFALG engine support
     [ available ]
der@somewhere:~/tmp/tmp$ 
der@somewhere:~/tmp/tmp$ 
der@somewhere:~/tmp/tmp$ openssl engines
Invalid command 'engines'; type "help" for a list.
der@somewhere:~/tmp/tmp$ openssl engine
(rdrand) Intel RDRAND engine
(dynamic) Dynamic engine loading support
der@somewhere:~/tmp/tmp$ openssl engine afalg
(afalg) AFALG engine support
der@somewhere:~/tmp/tmp$ openssl ciphers -v 'aes-128-cbc'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
der@somewhere:~/tmp/tmp$
der@somewhere:~/tmp/tmp$ find /usr/lib -name "*afalg*"
/usr/lib/x86_64-linux-gnu/engines-1.1/afalg.so
der@somewhere:~/tmp/tmp$
der@somewhere:~/tmp/tmp$ openssl enc -engine afalg -aes-128-cbc -in info.txt -out output.txt
engine "afalg" set.
enter aes-128-cbc encryption password:
Verifying - enter aes-128-cbc encryption password:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
der@somewhere:~/tmp/tmp$
der@somewhere:~/tmp/tmp$ 
der@somewhere:~/tmp/tmp$ openssl enc -d -engine afalg -aes-128-cbc -in output.txt -out dec.txt -pass pass:somepasswd
engine "afalg" set.
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
der@somewhere:~/tmp/tmp$ 
der@somewhere:~/tmp/tmp$ md5sum info.txt dec.txt 
c50829378ad3f6ad668b290ef8b17cc4  info.txt
c50829378ad3f6ad668b290ef8b17cc4  dec.txt
der@somewhere:~/tmp/tmp$

code

加载

int main() {
        int ret = 1;
        int type = 0;
        do{
                printf("please choose type: 0:exit 1:load_builtin, 2:init_crypto AFALG, 3:init_crypto DYNAMIC, 4:add_all_algorithms\n");
                (void)scanf(" %d",&type);
                switch(type){
                        case 0:
                                return 0;
                        case 1:
                                ENGINE_load_builtin_engines();
                                break;
                        case 2:
                                OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_AFALG, NULL);
                                break;
                        case 3:
                                OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_DYNAMIC, NULL);
                                break;
                        case 4:
                                OpenSSL_add_all_algorithms();
                                break;

                }

                ENGINE *e = ENGINE_by_id("afalg");
                if (e == NULL) {
                        printf("Can not load AFALG engine.\n");
                        continue;
                }
                printf("Load AFALG engine OK.\n");
                int rc = ENGINE_init(e);
                if (rc == 0) {
                        printf("Init AFALG engine fail.\n");
                        ENGINE_free(e);
                        continue;
                }
                printf("Init AFALG engine OK.\n");

                //now we can use afalg engine

第1种第3种可以加载,2,4种不行

使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/engine.h>

// colors used in printf
#define COLOR_NONE "\033[m"
#define COLOR_RED "\033[0;32;31m"
#define COLOR_LIGHT_RED "\033[1;31m"
#define COLOR_YELLOW "\033[1;33m"
#define COLOR_GREEN "\033[0;32;32m"
#define COLOR_BLUE "\033[0;32;34m"
#define COLOR_PURPLE "\033[0;32;35m"

// switch of printf
#if 1
#define PRINT(...) printf(__VA_ARGS__)
#else
#define PRINT(...)
#endif

#if 0
#define PRINTSUCCESS(...) printf(__VA_ARGS__)
#else
#define PRINTSUCCESS(...)
#endif

#if 1
#define PRINTFAIL(...) printf(__VA_ARGS__)
#else
#define PRINTFAIL(...)
#endif

// macros related to break
#define FREE_NOTNULL(ptr, func_name) \
    {                                \
        if (ptr != NULL)             \
        {                            \
            func_name(ptr);          \
            ptr = NULL;              \
        }                            \
    }

#define CALL_FUNC(ret, funSentence, errCase)                                                                     \
    {                                                                                                            \
        ret = funSentence;                                                                                       \
        if (errCase)                                                                                             \
        {                                                                                                        \
            PRINTFAIL(COLOR_RED "[%s][%d] " #funSentence " fail:" #errCase "\n" COLOR_NONE, __FILE__, __LINE__); \
            break;                                                                                               \
        }                                                                                                        \
        else                                                                                                     \
        {                                                                                                        \
            PRINTSUCCESS(COLOR_GREEN "[%s][%d] " #funSentence " success\n" COLOR_NONE, __FILE__, __LINE__);      \
        }                                                                                                        \
    }

#define CALL_FUNC_WITHIOUTBREAK(ret, funSentence, errCase)                                                       \
    {                                                                                                            \
        ret = funSentence;                                                                                       \
        if (errCase)                                                                                             \
        {                                                                                                        \
            PRINTFAIL(COLOR_RED "[%s][%d] " #funSentence " fail:" #errCase "\n" COLOR_NONE, __FILE__, __LINE__); \
        }                                                                                                        \
        else                                                                                                     \
        {                                                                                                        \
            PRINTSUCCESS(COLOR_GREEN "[%s][%d] " #funSentence " success\n" COLOR_NONE, __FILE__, __LINE__);      \
        }                                                                                                        \
    }

#define CALL_FUNC_NOTNULL(ret, funSentence) \
    CALL_FUNC(ret, funSentence, ret == NULL)

#define CALL_FUNC_POSITIVE(ret, funSentence) \
    CALL_FUNC(ret, funSentence, ret <= 0)

#define CALL_NBFUNC_NOTNULL(ret, funSentence) \
    CALL_FUNC_WITHIOUTBREAK(ret, funSentence, ret == NULL)

#define CALL_NBFUNC_POSITIVE(ret, funSentence) \
    CALL_FUNC_WITHIOUTBREAK(ret, funSentence, ret <= 0)

#define BUFFER_SIZE 256

static void print_hex(const char *info, unsigned char *data, unsigned int len)
{
    printf("%s[len:%d | 0x%x]\n", info, len, len);
    for (int i = 0; i < len; i++)
    {
        printf("%02x ", data[i]);
    }
    printf("\n");
}

static int test_afalg_aes_cbc(ENGINE *engine)
{
    EVP_CIPHER_CTX *ctx = NULL;
    const EVP_CIPHER *cipher;
    unsigned char key[] = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
                          "\x51\x2e\x03\xd5\x34\x12\x00\x06"
                          "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
                          "\x51\x2e\x03\xd5\x34\x12\x00\x06";
    unsigned char iv[] = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
                         "\xb4\x22\xda\x80\x2c\x9f\xac\x41";
    /* input = "Single block msg\n"  17Bytes*/
    unsigned char in[BUFFER_SIZE] = "\x53\x69\x6e\x67\x6c\x65\x20\x62"
                                    "\x6c\x6f\x63\x6b\x20\x6d\x73\x67\x0a";
    unsigned char ebuf[BUFFER_SIZE + 32];
    unsigned char dbuf[BUFFER_SIZE + 32];
    unsigned char encresult_128[] = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
                                    "\x27\x08\x94\x2d\xbe\x77\x18\x1a\x2d";
    unsigned char encresult_192[] = "\xf7\xe4\x26\xd1\xd5\x4f\x8f\x39"
                                    "\xb1\x9e\xe0\xdf\x61\xb9\xc2\x55\xeb";
    unsigned char encresult_256[] = "\xa0\x76\x85\xfd\xc1\x65\x71\x9d"
                                    "\xc7\xe9\x13\x6e\xae\x55\x49\xb4\x13";
    unsigned char *enc_result = NULL;

    int encl, encf, decl, decf;
    int ret = 0;
    int keysize_idx = 0;
    printf("please choose key len: 0:128, 1:192, 2:256 else:128\n");
    (void)scanf(" %d", &keysize_idx);

    do
    {
        switch (keysize_idx)
        {
        case 0:
            cipher = EVP_aes_128_cbc();
            enc_result = &encresult_128[0];
            break;
        case 1:
            cipher = EVP_aes_192_cbc();
            enc_result = &encresult_192[0];
            break;
        case 2:
            cipher = EVP_aes_256_cbc();
            enc_result = &encresult_256[0];
            break;
        default:
            cipher = EVP_aes_128_cbc();
            enc_result = &encresult_128[0];
            break;
        }
        CALL_FUNC_NOTNULL(ctx, EVP_CIPHER_CTX_new())
        print_hex("src data", in, BUFFER_SIZE);
        CALL_FUNC_POSITIVE(ret, EVP_CipherInit_ex(ctx, cipher, engine, key, iv, 1))
        CALL_FUNC_POSITIVE(ret, EVP_CipherUpdate(ctx, ebuf, &encl, in, BUFFER_SIZE))
        CALL_FUNC_POSITIVE(ret, EVP_CipherFinal_ex(ctx, ebuf + encl, &encf))

        encl += encf;
        print_hex("enc data", ebuf, encl);
        // CALL_FUNC(ret,memcmp(enc_result, ebuf, BUFFER_SIZE),ret != 0)

        CALL_FUNC_POSITIVE(ret, EVP_CIPHER_CTX_reset(ctx))
        CALL_FUNC_POSITIVE(ret, EVP_CipherInit_ex(ctx, cipher, engine, key, iv, 0))
        CALL_FUNC_POSITIVE(ret, EVP_CipherUpdate(ctx, dbuf, &decl, ebuf, encl))
        CALL_FUNC_POSITIVE(ret, EVP_CipherFinal_ex(ctx, dbuf + decl, &decf))
        print_hex("dec data", dbuf, decl);

        decl += decf;
        CALL_FUNC_POSITIVE(ret, decl == BUFFER_SIZE)
        CALL_FUNC(ret, memcmp(dbuf, in, BUFFER_SIZE), ret != 0)
        printf("engine enc dec success.\n");
        ret = 1;
    } while (0);
end:
    FREE_NOTNULL(ctx, EVP_CIPHER_CTX_free)
    return ret;
}

int test_engine_digest(ENGINE *engine)
{
    int ret = 0;
    const EVP_MD *md = NULL;
    EVP_MD_CTX *emctx = NULL;
    unsigned char data[128] = {1, 2, 4};
    unsigned char digestData[64] = {0};
    unsigned int digestSize = sizeof(digestData);
    const char *eName = NULL;
    do
    {
        CALL_FUNC_NOTNULL(eName, ENGINE_get_name(engine))
        printf("engine name:%s\n", eName);
        CALL_FUNC_POSITIVE(ret, ENGINE_register_digests(engine))               //
        CALL_FUNC_POSITIVE(ret, ENGINE_set_default(engine, ENGINE_METHOD_ALL)) // ENGINE_METHOD_DIGESTS))

        CALL_FUNC_NOTNULL(emctx, EVP_MD_CTX_new())
        CALL_FUNC_POSITIVE(ret, EVP_MD_CTX_init(emctx))
        CALL_FUNC_NOTNULL(md, EVP_md5())
        digestSize = sizeof(digestData);
        CALL_FUNC_POSITIVE(ret, EVP_DigestInit_ex(emctx, md, engine))
        CALL_FUNC_POSITIVE(ret, EVP_DigestUpdate(emctx, data, sizeof(data)))
        CALL_FUNC_POSITIVE(ret, EVP_DigestFinal(emctx, digestData, &digestSize))
        print_hex("MD5 3 segment result", digestData, digestSize);

        memset(digestData, 0, sizeof(digestData));
        digestSize = sizeof(digestData);
        // CALL_FUNC_POSITIVE(ret,EVP_DigestInit_ex(emctx,md,engine))
        CALL_FUNC_POSITIVE(ret, EVP_Digest(data, sizeof(data), digestData, &digestSize, md, engine))
        print_hex("MD5 1 segment result", digestData, digestSize);

        memset(digestData, 0, sizeof(digestData));
        digestSize = sizeof(digestData);
        CALL_FUNC_NOTNULL(md, EVP_sha1())
        CALL_FUNC_POSITIVE(ret, EVP_DigestInit_ex(emctx, md, engine))
        CALL_FUNC_POSITIVE(ret, EVP_DigestUpdate(emctx, data, sizeof(data)))
        CALL_FUNC_POSITIVE(ret, EVP_DigestFinal(emctx, digestData, &digestSize))
        print_hex("SHA1 3 segment result", digestData, digestSize);

        memset(digestData, 0, sizeof(digestData));
        digestSize = sizeof(digestData);
        CALL_FUNC_NOTNULL(md, EVP_sha256())
        CALL_FUNC_POSITIVE(ret, EVP_DigestInit_ex(emctx, md, engine))
        CALL_FUNC_POSITIVE(ret, EVP_DigestUpdate(emctx, data, sizeof(data)))
        CALL_FUNC_POSITIVE(ret, EVP_DigestFinal(emctx, digestData, &digestSize))
        print_hex("SHA256 3 segment result", digestData, digestSize);
    } while (0);
    // FREE_NOTNULL(md,EVP_md5xx) //do not need free
    FREE_NOTNULL(emctx, EVP_MD_CTX_free)
    return ret;
}

int main()
{
    int ret = 1;
    int type = 0;
    do
    {
        printf("please choose type: 0:exit 1:load_builtin, 2:init_crypto AFALG, 3:init_crypto DYNAMIC, 4:add_all_algorithms\n");
        (void)scanf(" %d", &type);
        switch (type)
        {
        case 0:
            return 0;
        case 1:
            ENGINE_load_builtin_engines();
            break;
        case 2:
            OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_AFALG, NULL);
            break;
        case 3:
            OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_DYNAMIC, NULL);
            break;
        case 4:
            OpenSSL_add_all_algorithms();
            break;
        }

        ENGINE *e = ENGINE_by_id("afalg");
        if (e == NULL)
        {
            printf("Can not load AFALG engine.\n");
            continue;
        }
        printf("Load AFALG engine OK.\n");
        int rc = ENGINE_init(e);
        if (rc == 0)
        {
            printf("Init AFALG engine fail.\n");
            ENGINE_free(e);
            continue;
        }
        printf("Init AFALG engine OK.\n");

        // now we can use afalg engine
        CALL_FUNC_POSITIVE(ret, test_afalg_aes_cbc(e))
        CALL_FUNC_POSITIVE(ret, test_engine_digest(e))

        // ENGINE_free(e);
        ENGINE_finish(e);
    } while (type != 0);
    return 0;
}
der@somewhere:~/tmp/tmp/engine$ gcc -o engine engine.c -lcrypto
der@somewhere:~/tmp/tmp/engine$ ./engine 
please choose type: 0:exit 1:load_builtin, 2:init_crypto AFALG, 3:init_crypto DYNAMIC, 4:add_all_algorithms
3
Load AFALG engine OK.
Init AFALG engine OK.
please choose key len: 0:128, 1:192, 2:256 else:128
2
src data[len:256 | 0x100]
53 69 6e 67 6c 65 20 62 6c 6f 63 6b 20 6d 73 67 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
enc data[len:272 | 0x110]
a0 76 85 fd c1 65 71 9d c7 e9 13 6e ae 55 49 b4 ca 9f 86 f1 4f 52 d9 66 6c a1 f9 25 ae 42 c6 d9 e6 f2 15 3a 08 14 c2 e0 02 06 de e2 c1 45 ba 02 dc 36 85 a8 2e 74 a3 68 b8 96 69 0f 78 59 34 50 77 85 24 00 f1 54 ea 9f 75 b7 61 c1 db a1 ad b3 3b b5 c1 c9 77 9f f0 f8 fc 95 f1 36 17 34 c5 03 41 43 1e 6e 69 e8 e1 88 fb d1 ac 0c 46 6e 71 26 52 a3 91 b3 87 dc 6a 16 e4 02 a8 a4 8b 4c 6a c1 ef 5d 92 3b ab 43 cc 80 34 5a c6 52 c6 48 8b a0 f5 14 12 85 55 78 92 80 30 5f f9 45 e1 fe 61 e9 02 da a1 69 19 a1 92 16 87 f2 a3 8d e3 e8 15 34 69 c2 40 69 2b 15 43 27 da 4e 56 15 d3 10 e5 55 58 8c d0 0e ee 2b 3f 00 57 e8 65 7f ac d5 01 af 9a 13 1a c0 ae ac b1 a8 01 46 f7 15 2d 26 22 b1 87 a0 ee db a3 fb 9d a3 94 77 91 e1 72 25 5e 9c 17 d6 d6 5f e9 3c 2f 0f bb be 79 1f 99 06 7e 37 68 67 9c 76 04 dc de e3 dc ed dd c9 32 fd dc 7d 
dec data[len:256 | 0x100]
53 69 6e 67 6c 65 20 62 6c 6f 63 6b 20 6d 73 67 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
engine enc dec success.
engine name:AFALG engine support
[engine.c][197] EVP_DigestInit_ex(emctx,md,engine) fail:ret <= 0
[engine.c][271] test_engine_digest(e) fail:ret <= 0
der@somewhere:~/tmp/tmp/engine$ 
der@somewhere:~/tmp/tmp/engine$

可以看到aes使用afalg引擎成功,但是digest使用引擎失败了。之前好像看到过说明,digest软算法很快,如果使用硬件加速引擎综合开销反而更大或者效率提升不明显,如果需要引擎支持digest需要编译openssl的时候指定相应标志。就这样。

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

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

相关文章

阳光倒灌高准直汽车抬头显示器HUD太阳光模拟器

阳光倒灌高准直汽车抬头显示器HUD太阳光模拟器是一种高级别的模拟设备&#xff0c;用于模拟太阳光的光谱、强度及照射角度&#xff0c;应用于太阳能电池板、光伏系统等领域的研究和测试。其参数包括光谱范围、光强度、光源、照射角度、均匀性和稳定性&#xff0c;可根据需求调整…

CVE-2022-33891 Apache Spark shell 命令注入漏洞分析

漏洞简介 Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的类Hadoop MapReduce的通用并行框架 Spark&#xff0c;拥有Hadoop MapReduce所具有的优点&#xff1b;但不同于MapReduce的…

Amuse:.NET application for stable diffusion

目录 Welcome to Amuse! Features Why Choose Amuse? Key Highlights Paint To Image Text To Image Image To Image Image Inpaint Model Manager Hardware Requirements Compute Requirements Memory Requirements System Requirements Realtime Requirements…

5.递归分治——2.如何逐步简化问题

思路 找到大问题到小问题的转移过程&#xff1a;把大问题分解为多个相似的小问题找到最小问题的解决方案&#xff1a;解决边界问题合并小问题的解决&#xff0c;得到整个问题的解决方案 例题 代码 #include <cstdio> #include <string> #include <map> #i…

Android14之深入理解sp模板类(二百零二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

pandas 函数

pandas是基于numpy数组构建的&#xff0c;但二者最大的不同是pandas是专门为处理表格和混杂数据设计的&#xff0c;比较契合统计分析中的表结构&#xff0c;而numpy更适合处理统一的数值数组数据。pandas数组结构有一维Series和二维DataFrame。 Series的字符串表现形式为&#…

用指针处理链表(二)

4建立动态链表 所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表&#xff0c;即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。 例11.8 写一函数建立一个有3名学生数据的单向动态链表。 先考虑实现此要求的算法(见图11.12)。 设3个指针变量:he…

使用 python 拆分 excel 文件

文章目录 1、安装虚拟环境&#xff08;在特定文件夹内&#xff09;2、脚本 split.sh3、运行脚本&#xff08;在特定文件夹内&#xff09;4、结果 1、安装虚拟环境&#xff08;在特定文件夹内&#xff09; brew install python3 xcode-select --install python3 -m venv my_pan…

基于nodejs+vue网购平台管理系统python-flask-django-php

本篇论文对网购平台管理系统的需求分析、功能设计、系统设计进行了较为详尽的阐述&#xff0c;并对系统的整体设计进行了阐述&#xff0c;并对各功能的实现和主要功能进行了说明&#xff0c;并附上了相应的操作界面图。 前端技术&#xff1a;nodejsvueelementui, Express 框架…

深入解析快速排序算法

深入解析快速排序算法 一、快速排序算法简介二、快速排序算法过程三、快速排序算法示例四、快速排序算法分析1. 时间复杂度&#xff1a;2. 空间复杂度&#xff1a;3. 稳定性&#xff1a; 五、快速排序算法优化1. 优化基准元素的选择&#xff1a;2. 优化小数组的排序&#xff1a…

初识云原生、虚拟化、DevOps

文章目录 K8S虚拟化DevOpsdevops平台搭建工具大数据架构 K8S master 主节点&#xff0c;控制平台&#xff0c;Master节点负责核心的调度、管理和运维&#xff0c;不需要很高性能&#xff0c;不跑任务&#xff0c;通常一个就行了&#xff0c;也可以开多个主节点来提高集群可用度…

Windows版 CUDA安装

目录 一、说明 二、安装工具下载 三、CUDA安装 四、cuDNN配置 五、验证安装是否成功 一、说明 windows10 版本安装 CUDA &#xff0c;首先需要下载两个安装包 CUDA toolkitcuDNN 官方教程 CUDA&#xff1a;https://docs.nvidia.com/cuda/cuda-installation-guide-micro…

[Android]创建Google Play内购aab白包

开发时需要调试Google内购&#xff0c;需要先往Google商店传一个白包上去。确定包名&#xff0c;然后进行内购产品创建。 1.创建一个空项目&#xff0c;填写正式名称和正式包名。 如果你只是为一个测试开发账号打白包&#xff0c;然后进行内购测试&#xff0c;这时包名随便写…

web前端面试题---->HTML、CSS

一.居中方法 block元素如何居中 margin&#xff1a;0 auto&#xff1b;position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);flex布局&#xff1a; 对父元素操作 &#xff1a; justify-content:center; al…

VsCode中安装codeium 显示failed to start language server

一、在VsCode的SSH Remote插件中安装Codeium 失败&#xff1a; 1、在插件Remote Explore中的SSH安装Codeium插件后提示无法下载语言服务器&#xff0c;如下图所示 2、去Codeium的仓库中找到对应版本的语言服务器包下载&#xff0c;然后解压并拷贝到远程服务器Ubuntu中的如下目…

Arduino+ESP8266+华为云物联网平台实现智能开关

前言 最近在做一个物联网项目&#xff0c;涉及到智能开关的开发。目前已经实现简单的TCP通信远程控制&#xff0c;但是考虑到后期的设备管理以及设备通信所需要的技术和服务器的维护成本&#xff0c;我决定将设备接入云平台。本文将详细阐述如何利用华为云的物联网平台&#x…

嵌入式下C/C++调用sqlite3简单开发

交叉编译sqlite3请关注我第一篇博文 sqlite3 交叉编译-CSDN博客 sqlite3的命令的简单使用&#xff08;增删改查&#xff0c;创建/删除表&#xff09;请关注我的上一篇博文 sqlite3嵌入式使用以及C/C代码开发-CSDN博客 一、新建文件夹 此文件夹用于放置工程&#xff0c;比如…

工作多年,如何从 CRUD Boy 转型为分布式系统架构师?解锁分布式系统的艺术:从零开始理解分布式系统架构与设计原理!...

编程是一门艺术&#xff0c;它的魅力在于创造。 65 哥已经工作5年了&#xff0c;一直做着简单重复的编程工作&#xff0c;活活熬成了一个只会 CRUD 的打工 boy。 65 哥&#xff1a;总是听大佬讲分布式分布式&#xff0c;什么才是分布式系统呢&#xff1f; 分布式系统是一个硬件…

环境影响与碳排放生命周期评估应用及案例分析

生命周期分析 (Life Cycle Analysis, LCA) 是评价一个产品系统生命周期整个阶段——从原材料的提取和加工&#xff0c;到产品生产、包装、市场营销、使用、再使用和产品维护&#xff0c;直至再循环和最终废物处置——的环境影响的工具。这种方法被认为是一种“从摇篮到坟墓”的…

R语言实现——网状 Meta 分析

近来年&#xff0c;网状 Meta 分析相关研究不断涌现&#xff0c;此类研究不但能发表在国内各大核心期刊上&#xff0c;还能在SCI期刊甚至医学4大刊上看到其身影。随手在pubmed上面一搜索&#xff0c;就能得到一万多篇相关文献。俨然成为医学文献研究的“大杀器”&#xff01; P…