RSA加密与签名的区别
文章目录
- 一、签名验签原理
- 二 RSAUtils 工具类
- 三、通过x509Certificate来获取CA证书的基本信息
- 四、 通过公钥获取公钥长度
一、签名验签原理
签名的本质其实就是加密,但是由于签名无需还原成明文,因此可以在加密前进行哈希处理。所以签名其实就是哈希+加密,而验签就是哈希+解密+比较。
签名过程:对明文做哈希,拼接头信息,用私钥进行加密,得到签名。
验签过程:用公钥解密签名,然后去除头信息,对明文做哈希,比较2段哈希值是否相同,相同则验签成功。
代码编写: Cipher 用于加密 Signature 用于签名
二 RSAUtils 工具类
package com.example.tr34.application.utils;import android.util.Base64;import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;import javax.crypto.Cipher;/*** date:2020/9/4 0004* author:wsm (Administrator)* funcation: 私钥有问题,base64解码失败*/public class RSAUtils {private static String RSA = "RSA";/*** *** RSA最大加密大小*/private final static int MAX_ENCRYPT_BLOCK = 117;/*** *** RSA最大解密大小*/private final static int MAX_DECRYPT_BLOCK = 128;/*** 随机生成RSA密钥对(默认密钥长度为1024)** @return*/public static KeyPair generateRSAKeyPair() {return generateRSAKeyPair(1024);}/*** 随机生成RSA密钥对** @param keyLength 密钥长度,范围:512~2048<br>* 一般1024* @return*/public static KeyPair generateRSAKeyPair(int keyLength) {try {KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);kpg.initialize(keyLength);return kpg.genKeyPair();} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;}}/*** 用公钥加密 <br>* 每次加密的字节数,不能超过密钥的长度值减去11** @param data 需加密数据的byte数据* @param publicKey 公钥* @return 加密后的byte型数据*/public static byte[] encryptData(byte[] data, PublicKey publicKey) {try {Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");// 编码前设定编码方式及密钥cipher.init(Cipher.ENCRYPT_MODE, publicKey);// 传入编码数据并返回编码结果return cipher.doFinal(data);} catch (Exception e) {e.printStackTrace();return null;}}/*** 用私钥解密** @param encryptedData 经过encryptedData()加密返回的byte数据* @param privateKey 私钥* @return*/public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) {try {Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(encryptedData);} catch (Exception e) {return null;}}/*** 通过公钥byte[](publicKey.getEncoded())将公钥还原,适用于RSA算法** @param keyBytes* @return* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException,InvalidKeySpecException {X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(RSA);PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}/*** 通过私钥byte[]将公钥还原,适用于RSA算法** @param keyBytes* @return* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException,InvalidKeySpecException {PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(RSA);PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}/*** 使用N、e值还原公钥** @param modulus* @param publicExponent* @return* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public static PublicKey getPublicKey(String modulus, String publicExponent)throws NoSuchAlgorithmException, InvalidKeySpecException {BigInteger bigIntModulus = new BigInteger(modulus);BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);KeyFactory keyFactory = KeyFactory.getInstance(RSA);PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}/*** 使用N、d值还原私钥** @param modulus* @param privateExponent* @return* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public static PrivateKey getPrivateKey(String modulus, String privateExponent)throws NoSuchAlgorithmException, InvalidKeySpecException {BigInteger bigIntModulus = new BigInteger(modulus);BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);KeyFactory keyFactory = KeyFactory.getInstance(RSA);PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}/*** 从字符串中加载公钥** @param publicKeyStr 公钥数据字符串* @throws Exception 加载公钥时产生的异常*/public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {try {byte[] buffer = Base64.decode(publicKeyStr,Base64.DEFAULT);KeyFactory keyFactory = KeyFactory.getInstance(RSA);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);return (RSAPublicKey) keyFactory.generatePublic(keySpec);} catch (NoSuchAlgorithmException e) {throw new Exception("无此算法");} catch (InvalidKeySpecException e) {throw new Exception("公钥非法");} catch (NullPointerException e) {throw new Exception("公钥数据为空");}}/*** 从字符串中加载私钥<br>* 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。** @param privateKeyStr* @return* @throws Exception*/public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {try {byte[] buffer = Base64.decode(privateKeyStr,Base64.DEFAULT);// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);KeyFactory keyFactory = KeyFactory.getInstance(RSA);return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);} catch (NoSuchAlgorithmException e) {throw new Exception("无此算法");} catch (InvalidKeySpecException e) {throw new Exception("私钥非法");} catch (NullPointerException e) {throw new Exception("私钥数据为空");}}/*** 用公钥分段加密 <br>* 每次加密的字节数,不能超过密钥的长度值减去11** @param data 需加密数据的byte数据* @param publicKey 公钥* @return 加密后的byte型数据*/public static byte[] PublicSubData(byte[] data, PublicKey publicKey) {try {Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");// 编码前设定编码方式及密钥cipher.init(Cipher.ENCRYPT_MODE, publicKey);// 传入编码数据并返回编码结果
// return cipher.doFinal(data);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0){if (inputLen - offSet > MAX_ENCRYPT_BLOCK){cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else{cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;} catch (Exception e) {e.printStackTrace();return null;}}/*** 用私钥分段解密** @param encryptedData 经过encryptedData()加密返回的byte数据* @param privateKey 私钥* @return*/public static byte[] PrivateSubData(byte[] encryptedData, PrivateKey privateKey) {try {Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE, privateKey);
// return cipher.doFinal(encryptedData);// 返回UTF-8编码的解密信息int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0){if (inputLen - offSet > MAX_DECRYPT_BLOCK){cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else{cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;} catch (Exception e) {return null;}}/*** 从文件中输入流中加载公钥** @param in 公钥输入流* @throws Exception 加载公钥时产生的异常*/public static PublicKey loadPublicKey(InputStream in) throws Exception {try {return loadPublicKey(readKey(in));} catch (IOException e) {throw new Exception("公钥数据流读取错误");} catch (NullPointerException e) {throw new Exception("公钥输入流为空");}}/*** 从文件中加载私钥** @param in 私钥文件名* @return 是否成功* @throws Exception*/public static PrivateKey loadPrivateKey(InputStream in) throws Exception {try {return loadPrivateKey(readKey(in));} catch (IOException e) {throw new Exception("私钥数据读取错误");} catch (NullPointerException e) {throw new Exception("私钥输入流为空");}}/*** 读取密钥信息** @param in* @return* @throws IOException*/private static String readKey(InputStream in) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(in));String readLine = null;StringBuilder sb = new StringBuilder();while ((readLine = br.readLine()) != null) {if (readLine.charAt(0) == '-') {continue;} else {sb.append(readLine);sb.append('\r');}}return sb.toString();}/*** 打印公钥信息** @param publicKey*/public static void printPublicKeyInfo(PublicKey publicKey) {RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;System.out.println("----------RSAPublicKey----------");System.out.println("Modulus.length=" + rsaPublicKey.getModulus().bitLength());System.out.println("Modulus=" + rsaPublicKey.getModulus().toString());System.out.println("PublicExponent.length=" + rsaPublicKey.getPublicExponent().bitLength());System.out.println("PublicExponent=" + rsaPublicKey.getPublicExponent().toString());}public static void printPrivateKeyInfo(PrivateKey privateKey) {RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;System.out.println("----------RSAPrivateKey ----------");System.out.println("Modulus.length=" + rsaPrivateKey.getModulus().bitLength());System.out.println("Modulus=" + rsaPrivateKey.getModulus().toString());System.out.println("PrivateExponent.length=" + rsaPrivateKey.getPrivateExponent().bitLength());System.out.println("PrivatecExponent=" + rsaPrivateKey.getPrivateExponent().toString());}
}
三、通过x509Certificate来获取CA证书的基本信息
//创建X509工厂类CertificateFactory cf = CertificateFactory.getInstance("X.509");//创建证书对象X509Certificate oCert = (X509Certificate)cf.generateCertificate(inStream);// inStream证书的传入数据inStream.close();SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");String info = null;//获得证书版本info = String.valueOf(oCert.getVersion());System.out.println("证书版本:"+info);//获得证书序列号info = oCert.getSerialNumber().toString(16);System.out.println("证书序列号:"+info);//获得证书有效期Date beforedate = oCert.getNotBefore();info = dateformat.format(beforedate);System.out.println("证书生效日期:"+info);Date afterdate = oCert.getNotAfter();info = dateformat.format(afterdate);System.out.println("证书失效日期:"+info);//获得证书主体信息info = oCert.getSubjectDN().getName();System.out.println("证书拥有者:"+info);//获得证书颁发者信息info = oCert.getIssuerDN().getName();System.out.println("证书颁发者:"+info);//获得证书签名算法名称info = oCert.getSigAlgName();System.out.println("证书签名算法:"+info);byte[] byt = oCert.getExtensionValue("1.2.86.11.7.9");String strExt = new String(byt);System.out.println("证书扩展域:" + strExt);byt = oCert.getExtensionValue("1.2.86.11.7.1.8");String strExt2 = new String(byt);System.out.println("证书扩展域2:" + strExt2);
四、 通过公钥获取公钥长度
通过X509Certificate.getPublicKey 获取公钥
/*** Gets the key length of supported keys* @param pk PublicKey used to derive the keysize* @return -1 if key is unsupported, otherwise a number >= 0. 0 usually means the length can not be calculated,* for example if the key is an EC key and the "implicitlyCA" encoding is used.*/public static int getKeyLength(final PublicKey pk) {int len = -1;if (pk instanceof RSAPublicKey) {final RSAPublicKey rsapub = (RSAPublicKey) pk;len = rsapub.getModulus().bitLength();} else if (pk instanceof JCEECPublicKey) {final JCEECPublicKey ecpriv = (JCEECPublicKey) pk;final org.bouncycastle.jce.spec.ECParameterSpec spec = ecpriv.getParameters();if (spec != null) {len = spec.getN().bitLength();} else {// We support the key, but we don't know the key lengthlen = 0;}} else if (pk instanceof ECPublicKey) {final ECPublicKey ecpriv = (ECPublicKey) pk;final java.security.spec.ECParameterSpec spec = ecpriv.getParams();if (spec != null) {len = spec.getOrder().bitLength(); // does this really return something we expect?} else {// We support the key, but we don't know the key lengthlen = 0;}} else if (pk instanceof DSAPublicKey) {final DSAPublicKey dsapub = (DSAPublicKey) pk;if ( dsapub.getParams() != null ) {len = dsapub.getParams().getP().bitLength();} else {len = dsapub.getY().bitLength();}}return len;}
相关文章:
RSA加密与签名的区别
文章目录 一、签名验签原理二 RSAUtils 工具类三、通过x509Certificate来获取CA证书的基本信息四、 通过公钥获取公钥长度 一、签名验签原理 签名的本质其实就是加密,但是由于签名无需还原成明文,因此可以在加密前进行哈希处理。所以签名其实就是哈希加…...

arcgis js api 4.x通过TileLayer类加载arcgis server10.2发布的切片服务跨域问题的解决办法
1.错误复现 2.解决办法 2.1去https://github.com/Esri/resource-proxy 网站下载代理配置文件,我下载的是最新的1.1.2版本,这里根据后台服务器配置情况不同有三种配置文件,此次我用到的是DotNet和Java. 2.2 DotNet配置 2.2.1 对proxy文件增加…...
如何让chatGPT给出高质量的回答?
如何让chatGPT给出高质量的回答? ChatGPT从入门到进阶教程合集_哔哩哔哩_bilibili 公式 【指令词】【背景】【输入】【输出要求】 1. 指令词 ——精准任务or命令 如:简述、解释、翻译、总结、润色 2. 背景 ——补充信息 如:简述一篇讲解…...
Java后端开发(八)-- idea(2022版)将commit(未push)的 本地仓库 的 单条commit记录 进行撤销
目录 1.修改Test01类后,提交到本地仓库 。 2.commit成功后,在Git =》Log中会显示,commit记录...

Mysql架构解析,InnoDB架构概述。
MySQL架构解析 Mysql整体架构 MySQL整体架构如下图所示: MySQL逻辑系统架构分为4层: 应用层MySQL服务层存储引擎层系统文件层 下面将对各层的功能和组件进行介绍,并探讨一条语句的执行过程。 应用层 应用层是MySQL体系架构的最上层,它…...

jmeter如何测试websocket接口?
jmeter做接口测试,很多人都是做http协议的接口,就有很多人问websocket的接口怎么测试啊? 首先,我们要明白,websocket接口是什么接口。 然后,我们怎么用jmeter测试? jmeter要测试websocket接口…...

15 Transformer 框架概述
整体框架 机器翻译流程(Transformer) 通过机器翻译来做解释 给一个输入,给出一个输出(输出是输入的翻译的结果) “我是一个学生” --》(通过 Transformer) I am a student 流程 1 编码器和解…...

[架构之路-241]:目标系统 - 纵向分层 - 企业信息化与企业信息系统(多台企业应用单机组成的企业信息网络)
目录 前言: 一、什么是信息系统:计算机软件硬件系统 1.1 什么是信息 1.2 什么是信息系统 1.3 什么是信息技术 1.4 什么是信息化与信息化转型 1.5 什么是数字化与数字化转型(信息化的前提) 1.6 数字化与信息化的比较 1.7 …...
flink中使用异步函数的几个注意事项
背景 在flink系统中,我们为了补充某个流事件成一个完整的记录,经常需要调用外部接口获取一些配置数据,流事件结合这些配置数据就可以组合成一条完整的记录,然而如果同步调用外部系统接口来实现,那么会有很大的性能瓶颈…...

QML之Repeater 控件使用
Repeater 控件是 重复作用 根据 model中的index 数量进行重复 废话不说 直接看如何用 当model 为数字时 Rectangle{height: 1200width: 500visible: trueanchors.fill: parentColumn{spacing: 20Repeater{model: 10delegate: Rectangle{width: 60height: 20color: index%2 …...
哈希树讲解
哈希树(HashTree)是哈希(Hash)算法的一种延续。传统数据结构中对如何避免哈希冲突都有一定的描述和解释,但是这些描述和解释都是泛泛而谈,并没有提出比较好的解决方案。这里所提到的哈希树(HashTree)算法就是要提供一种在理论上和实际应用中均能有效地处…...
vue 项目启动后一直不断的刷新停不下来
新建的vue 项目,配置了代理后项目一直刷新,停不下来,各种查找最后发现是vue.config.js 中的热更新配置项目开启的原因 const {defineConfig } require(vue/cli-service) const AutoImport require(unplugin-auto-import/webpack) const Co…...

makesense在线yolov5标注
文章目录 一、创建图片文件夹和label.txt二、在线标注数据 参考文章博主:风吹落叶花飘荡 一、创建图片文件夹和label.txt 创建一个放置图片的文件夹images,存放需要标注的图片(图片最好重命名为1,2,3…避免后面混淆) 创建label.t…...

python 之 矩阵相关操作
文章目录 1. **创建矩阵**:2. **矩阵加法**:3. **矩阵乘法**:4. **矩阵转置**:5. **元素级操作**:6. **汇总统计**:7. **逻辑操作**: 理解你的需求,我将为每个功能写一个单独的代码块…...
敢问路在何方
从2022年进入软件行业到现在,二十二年眨眼之间过去了,依然奋斗在编码第一线,挣扎在第一线,借此程序员佳节之际回顾一下这许多年的历程。 由于本人混得实在不好,工作过的地方都用某单位某公司来代替实际的,到…...

复习mysql中的事务
一个事务的开始和结尾必须是 start transaction | commit; rollback 事务特性 1.原子性:多个操作打包成一个整体,要么全部执行,要么一个都不执行。 不过这里的“一个都不执行”并不是真正的全不执行,只是看起来与没执行一样。…...

力扣刷题 day52:10-22
1.数组拆分 给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。 返回该 最大总和 。 方法一:排序 #方法一:排序 def arrayPai…...

ELK概述部署和Filebeat 分布式日志管理平台部署
ELK概述部署、Filebeat 分布式日志管理平台部署 一、ELK 简介二、ELK部署2.1、部署准备2.2、优化elasticsearch用户拥有的内存权限2.3、启动elasticsearch是否成功开启2.4、浏览器查看节点信息2.5、安装 Elasticsearch-head 插件2.6、ELK Logstash 部署(在 Apache 节…...

分享一下我家网络机柜,家庭网络设备推荐
家里网络机柜搞了几天终于搞好了,非专业的,走线有点乱,勿喷。 从上到下的设备分别是: 无线路由器(当ap用):TL-XDR6088 插排:德木pdu机柜插排 硬盘录像机:TL-NVR6108-L8P 第二排左边…...
uboot移植之mx6ull_alientek_nand.h文件详解三
一. 简介 mx6ull_alientek_nand.h文件是 开发板的 uboot的一个配置文件。每个开发板都有一个 .h的配置文件。 mx6ull_alientek_nand.h 文件其实是 之前针对正点原子ALPHA开发板移植的 Uboot配置文件。 本文继上一篇文章的学习,地址如下:uboot移植之m…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...