计算机工作原理:从硬件到系统的奥秘,vscode 不能跳转 ERR_OSSL_EVP_BAD_DECRYPT。

计算机的基本组成

计算机主要由五大核心部件组成:输入设备、输出设备、存储器、运算器和控制器。输入设备(如键盘、鼠标)将外部信息转换为计算机可处理的数字信号。输出设备(如显示器、打印机)将处理结果转换为人类可感知的形式。存储器分为内存(RAM)和外存(硬盘),前者用于临时存储运行中的程序和数据,后者用于长期存储。运算器(ALU)执行算术和逻辑运算,控制器(CPU核心部件)协调各部件工作。

现代计算机采用冯·诺依曼体系结构,其核心特征是"存储程序"概念——程序和数据以二进制形式共同存储在内存中,由控制器按顺序读取并执行。这种设计使得计算机通过更换程序就能完成不同任务,无需重新设计硬件电路。

二进制与数据处理

计算机使用二进制(0和1)表示信息,因为电子元件易于实现两种稳定状态(如高/低电压)。每个二进制位称为比特(bit),8比特构成字节(byte),可表示256种状态(2^8)。数字、文字、图像等数据最终都被转换为二进制形式处理。例如:

  • 数字:直接以二进制补码形式存储
  • 字符:通过ASCII/Unicode编码转换(如'A'对应01000001)
  • 图像:分解为像素点,每个像素用二进制表示颜色值

CPU处理的指令也是二进制代码,例如x86架构中"ADD EAX, EBX"对应的机器码可能是01 D8。指令集架构(ISA)定义了这些二进制编码与操作的对应关系。

CPU执行流程

中央处理器(CPU)通过指令周期完成工作:取指令→解码→执行→写回。时钟信号同步各步骤,现代CPU主频可达GHz级别,代表每秒完成数十亿次基本操作。典型执行过程如下:

  1. 取指阶段:从内存读取下一条指令到指令寄存器(PC计数器指向内存地址)
  2. 译码阶段:解析指令类型和操作数(如识别是加法运算还是数据移动)
  3. 执行阶段:运算器执行操作(如ALU完成加法计算)
  4. 访存阶段:如需访问内存则读取/写入数据
  5. 写回阶段:将结果保存到寄存器或内存

现代CPU采用流水线技术,使不同指令的各阶段重叠执行,显著提升效率。例如当第一条指令处于执行阶段时,第二条指令已开始译码,第三条指令开始取指。

存储层次结构

计算机存储系统采用金字塔式层次结构,自上而下容量增大但速度降低:

  • 寄存器:CPU内部,纳秒级访问,容量最小(如x86的16个通用寄存器)
  • 高速缓存(Cache):SRAM实现,分L1/L2/L3三级,速度比内存快5-10倍
  • 主存(RAM):DRAM实现,GB级容量,断电丢失数据
  • 外存(HDD/SSD):持久化存储,TB级容量,速度比内存慢千倍以上

这种结构通过局部性原理优化性能:时间局部性(近期访问的数据很可能再次访问)和空间局部性(相邻数据很可能被连续访问)。缓存通过预取和替换算法(如LRU)利用这些特性。

操作系统的作用

操作系统作为软件与硬件的桥梁,主要功能包括:

  • 进程管理:通过时间片轮转实现多任务,每个进程拥有独立的虚拟地址空间
  • 内存管理:虚拟内存机制将磁盘空间扩展为"内存",通过分页/分段实现隔离
  • 文件系统:以目录树形式组织外存数据,提供打开/读写/权限控制等操作接口
  • 设备驱动:标准化硬件访问方式,使应用程序无需关心具体设备细节

系统调用(System Call)是应用程序请求操作系统服务的唯一入口,如Linux的write()用于向文件输出数据。操作系统通过中断机制响应这些请求,在用户态和内核态间切换。


这篇文章涵盖了计算机的核心工作机制,从硬件基础到系统软件协作,适合作为入门级技术概览。实际计算机系统还涉及总线通信、并行计算、网络协议等更复杂机制,但以上原理构成了所有计算设备的共同基础。

EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc) ; int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc) { return evp_cipher_init_internal(ctx, cipher, impl, key, iv, enc, 0, NULL); } static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc, uint8_t is_pipeline, const OSSL_PARAM params[]) { int n; #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) ENGINE *tmpimpl = NULL; #endif /* * enc == 1 means we are encrypting. * enc == 0 means we are decrypting. * enc == -1 means, use the previously initialised value for encrypt/decrypt */ if (enc == -1) { enc = ctx->encrypt; } else { if (enc) enc = 1; ctx->encrypt = enc; } if (cipher == NULL && ctx->cipher == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); return 0; } /* Code below to be removed when legacy support is dropped. */ if (is_pipeline) goto nonlegacy; #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) /* * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so * this context may already have an ENGINE! Try to avoid releasing the * previous handle, re-querying for an ENGINE, and having a * reinitialisation, when it may all be unnecessary. */ if (ctx->engine && ctx->cipher && (cipher == NULL || cipher->nid == ctx->cipher->nid)) goto skip_to_init; if (cipher != NULL && impl == NULL) { /* Ask if an ENGINE is reserved for this job */ tmpimpl = ENGINE_get_cipher_engine(cipher->nid); } #endif /* * If there are engines involved then we should use legacy handling for now. */ if (ctx->engine != NULL #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) || tmpimpl != NULL #endif || impl != NULL || (cipher != NULL && cipher->origin == EVP_ORIG_METH) || (cipher == NULL && ctx->cipher != NULL && ctx->cipher->origin == EVP_ORIG_METH)) { if (ctx->cipher == ctx->fetched_cipher) ctx->cipher = NULL; EVP_CIPHER_free(ctx->fetched_cipher); ctx->fetched_cipher = NULL; goto legacy; } /* * Ensure a context left lying around from last time is cleared * (legacy code) */ if (cipher != NULL && ctx->cipher != NULL) { if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx)) return 0; OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); ctx->cipher_data = NULL; } /* Start of non-legacy code below */ nonlegacy: /* Ensure a context left lying around from last time is cleared */ if (cipher != NULL && ctx->cipher != NULL) { unsigned long flags = ctx->flags; EVP_CIPHER_CTX_reset(ctx); /* Restore encrypt and flags */ ctx->encrypt = enc; ctx->flags = flags; } if (cipher == NULL) cipher = ctx->cipher; if (cipher->prov == NULL) { #ifdef FIPS_MODULE /* We only do explicit fetches inside the FIPS module */ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; #else EVP_CIPHER *provciph = EVP_CIPHER_fetch(NULL, cipher->nid == NID_undef ? "NULL" : OBJ_nid2sn(cipher->nid), ""); if (provciph == NULL) return 0; cipher = provciph; EVP_CIPHER_free(ctx->fetched_cipher); ctx->fetched_cipher = provciph; #endif } if (!ossl_assert(cipher->prov != NULL)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } if (cipher != ctx->fetched_cipher) { if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } EVP_CIPHER_free(ctx->fetched_cipher); /* Coverity false positive, the reference counting is confusing it */ /* coverity[use_after_free] */ ctx->fetched_cipher = (EVP_CIPHER *)cipher; } ctx->cipher = cipher; if (is_pipeline && !EVP_CIPHER_can_pipeline(cipher, enc)) { ERR_raise(ERR_LIB_EVP, EVP_R_PIPELINE_NOT_SUPPORTED); return 0; } if (ctx->algctx == NULL) { ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); if (ctx->algctx == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { /* * If this ctx was already set up for no padding then we need to tell * the new cipher about it. */ if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) return 0; } #ifndef FIPS_MODULE /* * Fix for CVE-2023-5363 * Passing in a size as part of the init call takes effect late * so, force such to occur before the initialisation. * * The FIPS provider's internal library context is used in a manner * such that this is not an issue. */ if (params != NULL) { OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; OSSL_PARAM *q = param_lens; const OSSL_PARAM *p; p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); if (p != NULL) memcpy(q++, p, sizeof(*q)); /* * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synonym for * OSSL_CIPHER_PARAM_IVLEN so both are covered here. */ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); if (p != NULL) memcpy(q++, p, sizeof(*q)); if (q != param_lens) { if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); return 0; } } } #endif if (is_pipeline) return 1; if (enc) { if (ctx->cipher->einit == NULL) { /* * We still should be able to set the IV using the new API * if the key is not specified and old API is not available */ if (key == NULL && ctx->cipher->einit_skey != NULL) { return ctx->cipher->einit_skey(ctx->algctx, NULL, iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } return ctx->cipher->einit(ctx->algctx, key, key == NULL ? 0 : EVP_CIPHER_CTX_get_key_length(ctx), iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } if (ctx->cipher->dinit == NULL) { /* * We still should be able to set the IV using the new API * if the key is not specified and old API is not available */ if (key == NULL && ctx->cipher->dinit_skey != NULL) { return ctx->cipher->dinit_skey(ctx->algctx, NULL, iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } return ctx->cipher->dinit(ctx->algctx, key, key == NULL ? 0 : EVP_CIPHER_CTX_get_key_length(ctx), iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); /* Code below to be removed when legacy support is dropped. */ legacy: if (cipher != NULL) { /* * Ensure a context left lying around from last time is cleared (we * previously attempted to avoid this if the same ENGINE and * EVP_CIPHER could be used). */ if (ctx->cipher) { unsigned long flags = ctx->flags; EVP_CIPHER_CTX_reset(ctx); /* Restore encrypt and flags */ ctx->encrypt = enc; ctx->flags = flags; } #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) if (impl != NULL) { if (!ENGINE_init(impl)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } else { impl = tmpimpl; } if (impl != NULL) { /* There's an ENGINE for this job ... (apparently) */ const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); if (c == NULL) { /* * One positive side-effect of US's export control history, * is that we should at least be able to avoid using US * misspellings of "initialisation"? */ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } /* We'll use the ENGINE's private cipher definition */ cipher = c; /* * Store the ENGINE functional reference so we know 'cipher' came * from an ENGINE and we need to release it when done. */ ctx->engine = impl; } else { ctx->engine = NULL; } #endif ctx->cipher = cipher; if (ctx->cipher->ctx_size) { ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); if (ctx->cipher_data == NULL) { ctx->cipher = NULL; return 0; } } else { ctx->cipher_data = NULL; } ctx->key_len = cipher->key_len; /* Preserve wrap enable flag, zero everything else */ ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { ctx->cipher = NULL; ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } } #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) skip_to_init: #endif if (ctx->cipher == NULL) return 0; /* we assume block size is a power of 2 in *cryptUpdate */ OPENSSL_assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 || ctx->cipher->block_size == 16); if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); return 0; } if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_CUSTOM_IV) == 0) { switch (EVP_CIPHER_CTX_get_mode(ctx)) { case EVP_CIPH_STREAM_CIPHER: case EVP_CIPH_ECB_MODE: break; case EVP_CIPH_CFB_MODE: case EVP_CIPH_OFB_MODE: ctx->num = 0; /* fall-through */ case EVP_CIPH_CBC_MODE: n = EVP_CIPHER_CTX_get_iv_length(ctx); if (n < 0 || n > (int)sizeof(ctx->iv)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); return 0; } if (iv != NULL) memcpy(ctx->oiv, iv, n); memcpy(ctx->iv, ctx->oiv, n); break; case EVP_CIPH_CTR_MODE: ctx->num = 0; /* Don't reuse IV for CTR mode */ if (iv != NULL) { n = EVP_CIPHER_CTX_get_iv_length(ctx); if (n <= 0 || n > (int)sizeof(ctx->iv)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); return 0; } memcpy(ctx->iv, iv, n); } break; default: return 0; } } if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { if (!ctx->cipher->init(ctx, key, iv, enc)) return 0; } ctx->buf_len = 0; ctx->final_used = 0; ctx->block_mask = ctx->cipher->block_size - 1; return 1; }
10-30
int decrypt_aes_gcm( const unsigned char *ciphertext, int ciphertext_len, const unsigned char *tag, const unsigned char *key, const unsigned char *iv, int iv_len, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx = NULL; int len, plaintext_len; // 创建上下文 if (!(ctx = EVP_CIPHER_CTX_new())) { fprintf(stderr, "EVP_CIPHER_CTX_new failed\n"); return -1; } // 初始化:选择算法 if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) <= 0) { fprintf(stderr, "EVP_DecryptInit_ex (setup) failed\n"); goto err; } // 设置 IV 长度 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL) <= 0) { fprintf(stderr, "EVP_CIPHER_CTX_ctrl (SET_IVLEN) failed\n"); goto err; } // 设置 key 和 iv if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) <= 0) { fprintf(stderr, "EVP_DecryptInit_ex (key/iv) failed\n"); goto err; } if (!ctx || !plaintext || !len || (!ciphertext && ciphertext_len > 0)) { fprintf(stderr, "Invalid null argument!\n"); return -1; } // 解密数据 if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) <= 0) { fprintf(stderr, "EVP_DecryptUpdate failed\n"); goto err; } plaintext_len = len; // 设置认证标签(必须在 Final 前设置) if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)tag) <= 0) { fprintf(stderr, "EVP_CIPHER_CTX_ctrl (SET_TAG) failed\n"); goto err; } // 完成解密并验证 tag if (EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &len) > 0) { plaintext_len += len; EVP_CIPHER_CTX_free(ctx); return plaintext_len; // 成功返回明文字节数 } else { fprintf(stderr, "Authentication failed! Wrong key/tag/iv?\n"); goto err; } err: ERR_print_errors_fp(stderr); // 打印 OpenSSL 错误栈 EVP_CIPHER_CTX_free(ctx); return -1; } 优化这段代码,兼容openssl3.0
10-31
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值