鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥协商(ArkTS)】

密钥协商(ArkTS)

以协商密钥类型为X25519 256,并密钥仅在HUKS内使用为例,完成密钥协商。

开发步骤

生成密钥

设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成]或[密钥导入]。

密钥生成时,可指定参数HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识基于该密钥协商出的密钥是否由HUKS管理。

  • 当TAG设置为HUKS_STORAGE_ONLY_USED_IN_HUKS时,表示基于该密钥协商出的密钥,由HUKS管理,可保证协商密钥全生命周期不出安全环境。
  • 当TAG设置为HUKS_STORAGE_KEY_EXPORT_ALLOWED时,表示基于该密钥协商出的密钥,返回给调用方管理,由业务自行保证密钥安全。
  • 若业务未设置TAG的具体值,表示基于该密钥协商出的密钥,即可由HUKS管理,也可返回给调用方管理,业务可在后续协商时再选择使用何种方式保护密钥。
  • 开发前请熟悉鸿蒙开发指导文档gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。

导出密钥

设备A、B导出非对称密钥对的公钥材料。

密钥协商

设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。

密钥协商时,可指定参数HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识协商得到的密钥是否由HUKS管理。

生成协商规格
HUKS_STORAGE_ONLY_USED_IN_HUKSHUKS_STORAGE_ONLY_USED_IN_HUKS密钥由HUKS管理
HUKS_STORAGE_KEY_EXPORT_ALLOWEDHUKS_STORAGE_KEY_EXPORT_ALLOWED密钥返回给调用方管理
未指定TAG具体值HUKS_STORAGE_ONLY_USED_IN_HUKS密钥由HUKS管理
未指定TAG具体值HUKS_STORAGE_KEY_EXPORT_ALLOWED密钥返回给调用方管理
未指定TAG具体值 HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿未指定TAG具体值密钥返回给调用方管理

搜狗高速浏览器截图20240326151547.png

注:协商时指定的TAG值,不可与生成时指定的TAG值冲突。表格中仅列举有效的指定方式。

删除密钥

当密钥废弃不用时,设备A、B均需要删除密钥。

下面分别以X25519 与 DH密钥为例,进行协商。

/*
*以下以X25519 256密钥的Promise操作使用为例
*/
import { huks } from '@kit.UniversalKeystoreKit';/*
* 确定密钥别名和封装密钥属性参数集
*/
let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
let agreeX25519InData = 'AgreeX25519TestIndata';
let finishOutData: Uint8Array;
let handle: number;
let exportKey: Uint8Array;
let exportKeyFirst: Uint8Array;
let exportKeySecond: Uint8Array;
/* 集成生成密钥参数集 */
let properties: Array<huks.HuksParam> = [{tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_X25519,
}, {tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
}, {tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
}, {tag: huks.HuksTag.HUKS_TAG_DIGEST,value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
}, {tag: huks.HuksTag.HUKS_TAG_PADDING,value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
}, {tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,value: huks.HuksCipherMode.HUKS_MODE_CBC,
}, {tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
}];
let HuksOptions: huks.HuksOptions = {properties: properties,inData: new Uint8Array(new Array())
}
/* 集成第一个协商参数集 */
const finishProperties: Array<huks.HuksParam> = [{tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
}, {tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,value: true
}, {tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_AES,
}, {tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
}, {tag: huks.HuksTag.HUKS_TAG_PURPOSE,value:huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
}, {tag: huks.HuksTag.HUKS_TAG_DIGEST,value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
}, {tag: huks.HuksTag.HUKS_TAG_PADDING,value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
}, {tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,value: huks.HuksCipherMode.HUKS_MODE_ECB,
}];
let finishOptionsFirst: huks.HuksOptions = {properties: [...finishProperties, {tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,value: StringToUint8Array(srcKeyAliasFirst + 'final'),}],inData: StringToUint8Array(agreeX25519InData)
}
/* 集成第二个协商参数集 */
let finishOptionsSecond: huks.HuksOptions = {properties: [...finishProperties, {tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,value: StringToUint8Array(srcKeyAliasSecond + 'final'),}],inData: StringToUint8Array(agreeX25519InData)
}function StringToUint8Array(str: string) {let arr: number[] = new Array();for (let i = 0, j = str.length; i < j; ++i) {arr.push(str.charCodeAt(i));}return new Uint8Array(arr);
}class throwObject {isThrow: boolean = false
}/* 生成密钥 */
function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<void>((resolve, reject) => {try {huks.generateKeyItem(keyAlias, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/* 调用generateKeyItem生成密钥 */
async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {console.info(`enter promise generateKeyItem`);let throwObject: throwObject = { isThrow: false };try {await generateKeyItem(keyAlias, huksOptions, throwObject).then((data) => {console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: generateKeyItem failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: generateKeyItem input arg invalid, ${JSON.stringify(error)}`);}
}/*初始化密钥会话接口,并获取一个句柄(必选)和挑战值(可选)*/
function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<huks.HuksSessionHandle>((resolve, reject) => {try {huks.initSession(keyAlias, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/*调用initSession获取handle*/
async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) {console.info(`enter promise doInit`);let throwObject: throwObject = { isThrow: false };try {await initSession(keyAlias, huksOptions, throwObject).then((data) => {console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);handle = data.handle;}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: doInit failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`);}
}/* 分段添加密钥操作的数据并进行相应的密钥操作,输出处理数据 */
function updateSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<huks.HuksReturnResult>((resolve, reject) => {try {huks.updateSession(handle, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/* 调用updateSession进行协商操作 */
async function publicUpdateFunc(handle: number, huksOptions: huks.HuksOptions) {console.info(`enter promise doUpdate`);let throwObject: throwObject = { isThrow: false };try {await updateSession(handle, huksOptions, throwObject).then((data) => {console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`);}
}/* 结束密钥会话并进行相应的密钥操作,输出处理数据 */
function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<huks.HuksReturnResult>((resolve, reject) => {try {huks.finishSession(handle, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/* 调用finishSession结束操作 */
async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) {console.info(`enter promise doFinish`);let throwObject: throwObject = { isThrow: false };try {await finishSession(handle, huksOptions, throwObject).then((data) => {finishOutData = data.outData as Uint8Array;console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: doFinish failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: doFinish input arg invalid, ${JSON.stringify(error)}`);}
}/* 导出密钥 */
function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<huks.HuksReturnResult>((resolve, reject) => {try {huks.exportKeyItem(keyAlias, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/* 调用exportKeyItem导出公钥操作 */
async function publicExportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {console.info(`enter promise export`);let throwObject: throwObject = { isThrow: false };try {await exportKeyItem(keyAlias, huksOptions, throwObject).then((data) => {console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`);exportKey = data.outData as Uint8Array;}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: exportKeyItem failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: exportKeyItem input arg invalid, ${JSON.stringify(error)}`);}
}/* 删除密钥操作 */
function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {return new Promise<void>((resolve, reject) => {try {huks.deleteKeyItem(keyAlias, huksOptions, (error, data) => {if (error) {reject(error);} else {resolve(data);}});} catch (error) {throwObject.isThrow = true;throw (error as Error);}});
}/* 调用deleteKeyItem删除密钥操作 */
async function publicDeleteKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {console.info(`enter promise deleteKeyItem`);let throwObject: throwObject = { isThrow: false };try {await deleteKeyItem(keyAlias, huksOptions, throwObject).then((data) => {console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`);}).catch((error: Error) => {if (throwObject.isThrow) {throw (error as Error);} else {console.error(`promise: deleteKeyItem failed, ${JSON.stringify(error)}`);}});} catch (error) {console.error(`promise: deleteKeyItem input arg invalid, ${JSON.stringify(error)}`);}
}async function testAgree() {/* 1.确定密钥别名并集成并集成要参数集 A设备:srcKeyAliasFirst  B设备:srcKeyAliasSecond*//* 2.设备A生成密钥 */await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions);/* 3.设备B生成密钥 */await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions);/* 4.设备A、B导出非对称密钥的公钥 */await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions);exportKeyFirst = exportKey;await publicExportKeyFunc(srcKeyAliasSecond, HuksOptions);exportKeySecond = exportKey;/* 5.对第一个密钥进行协商(三段式)*/await publicInitFunc(srcKeyAliasFirst, HuksOptions);HuksOptions.inData = exportKeySecond;await publicUpdateFunc(handle, HuksOptions);await publicFinishFunc(handle, finishOptionsFirst);/* 5.对第二个密钥进行协商(三段式) */await publicInitFunc(srcKeyAliasSecond, HuksOptions);HuksOptions.inData = exportKeyFirst;await publicUpdateFunc(handle, HuksOptions);await publicFinishFunc(handle, finishOptionsSecond);/* 6.设备A、B删除密钥 */await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions);await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions);
}

下面以DH密钥协商为例

/**以下以 DH密钥的Promise操作使用为例*/
import { huks } from '@kit.UniversalKeystoreKit'function StringToUint8Array(str: string) {let arr: number[] = []for (let i = 0, j = str.length; i < j; ++i) {arr.push(str.charCodeAt(i))}return new Uint8Array(arr)
}function Uint8ArrayToBigInt(arr: Uint8Array): bigint {let i = 0const byteMax: bigint = BigInt('0x100')let result: bigint = BigInt('0')while (i < arr.length) {result = result * byteMaxresult = result + BigInt(arr[i])i += 1}return result
}const dhAgree: Array<huks.HuksParam> = [{tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_DH,
}, {tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
}]
const dh2048Agree: Array<huks.HuksParam> = [...dhAgree, {tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048,
}]
const dhGenOptions: huks.HuksOptions = {properties: dh2048Agree,inData: new Uint8Array([])
}
const emptyOptions: huks.HuksOptions = {properties: [],inData: new Uint8Array([])
}async function HuksDhAgreeExportKey(keyAlias: string,peerPubKey: huks.HuksReturnResult): Promise<huks.HuksReturnResult> {const initHandle = await huks.initSession(keyAlias, dhGenOptions)const dhAgreeUpdateBobPubKey: huks.HuksOptions = {properties: [...dh2048Agree, {tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,value: huks.HuksKeyStorageType.HUKS_STORAGE_KEY_EXPORT_ALLOWED,}],inData: peerPubKey.outData}await huks.updateSession(initHandle.handle, dhAgreeUpdateBobPubKey)return await huks.finishSession(initHandle.handle, emptyOptions)
}async function HuksDhAgreeExportTest(aliasA: string, aliasB: string,pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult) {const agreedKeyFromAlice = await HuksDhAgreeExportKey(aliasA, pubKeyB)console.info(`ok! agreedKeyFromAlice export is 0x${Uint8ArrayToBigInt(agreedKeyFromAlice.outData).toString(16)}`)const agreedKeyFromBob = await HuksDhAgreeExportKey(aliasB, pubKeyA)console.info(`ok! agreedKeyFromBob export is 0x${Uint8ArrayToBigInt(agreedKeyFromBob.outData).toString(16)}`)
}async function HuksDhAgreeInHuks(keyAlias: string, peerPubKey: huks.HuksReturnResult,aliasAgreedKey: string): Promise<huks.HuksReturnResult> {const onlyUsedInHuks: Array<huks.HuksParam> = [{tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG,value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,}, {tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,}]const dhAgreeInit: huks.HuksOptions = {properties: [...dhAgree,{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, },...onlyUsedInHuks],inData: new Uint8Array([])}const dhAgreeFinishParams: Array<huks.HuksParam> = [...onlyUsedInHuks,{ tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, value: true },{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },{tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT}]const handle = await huks.initSession(keyAlias, dhAgreeInit)const dhAgreeUpdatePubKey: huks.HuksOptions = {properties: [...dhAgree, ...onlyUsedInHuks],inData: peerPubKey.outData}await huks.updateSession(handle.handle, dhAgreeUpdatePubKey)const dhAgreeAliceFinnish: huks.HuksOptions = {properties: [...dhAgreeFinishParams, {tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, value: StringToUint8Array(aliasAgreedKey)}], inData: new Uint8Array([])}return await huks.finishSession(handle.handle, dhAgreeAliceFinnish)
}async function HuksDhAgreeInHuksTest(aliasA: string, aliasB: string,pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult,aliasAgreedKeyFromA: string, aliasAgreedKeyFromB: string) {const finishAliceResult = await HuksDhAgreeInHuks(aliasA, pubKeyB, aliasAgreedKeyFromA)console.info(`ok! finishAliceResult in huks is 0x${Uint8ArrayToBigInt(finishAliceResult.outData).toString(16)}`)const aliceAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromA, emptyOptions)console.info(`ok! aliceAgreedExist in huks is ${aliceAgreedExist}`)const finishBobResult = await HuksDhAgreeInHuks(aliasB, pubKeyA, aliasAgreedKeyFromB)console.info(`ok! finishBobResult in huks is 0x${Uint8ArrayToBigInt(finishBobResult.outData).toString(16)}`)const bobAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromB, emptyOptions)console.info(`ok! bobAgreedExist in huks is ${bobAgreedExist}`)await huks.deleteKeyItem(aliasAgreedKeyFromA, emptyOptions)await huks.deleteKeyItem(aliasAgreedKeyFromB, emptyOptions)
}export default async function HuksDhAgreeTest() {const aliasAlice = 'alice'const aliasBob = 'bob'/* 调用generateKeyItem生成别名为alice与bob的两个密钥 */await huks.generateKeyItem(aliasAlice, dhGenOptions)await huks.generateKeyItem(aliasBob, dhGenOptions)/* 导出非对称密钥alice与bob的的公钥 */const pubKeyAlice = await huks.exportKeyItem(aliasAlice, emptyOptions)const pubKeyBob = await huks.exportKeyItem(aliasBob, emptyOptions)/* 开始协商,协商生成的密钥返回给业务管理 */await HuksDhAgreeExportTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob)/* 开始协商,协商生成的密钥由HUKS管理 */await HuksDhAgreeInHuksTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob, 'agreedKeyFromAlice', 'agreedKeyFromBob')await huks.deleteKeyItem(aliasAlice, emptyOptions)await huks.deleteKeyItem(aliasBob, emptyOptions)
}

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

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

相关文章

LLM-文本分块(langchain)与向量化(阿里云DashVector)存储,嵌入LLM实践

文章目录 前言向量、令牌、嵌入分块按字符拆分按字符递归拆分按token拆分 向量化使用 TextEmbedding 实现语义搜索数据准备通过 DashScope 生成 Embedding 向量通过 DashVector 构建检索&#xff1a;向量入库语义检索&#xff1a;向量查询完整代码 总结 前言 Transformer 架构…

[C++][ProtoBuf][Proto3语法][三]详细讲解

目录 1.默认值2.更新消息1.更新规则2.保留字段reserved 3.未知字段1.是什么&#xff1f;2.未知字段从哪获取 4.前后兼容性5.选项option1.选项分类2.常用选项列举3.设置自定义选项 1.默认值 反序列化消息时&#xff0c;如果被反序列化的⼆进制序列中不包含某个字段&#xff0c;…

基于Spring Boot的旅游信息推荐信息系统设计与实现(源码+lw+部署+讲解)

技术指标 开发语言&#xff1a;Java 框架&#xff1a;Spring BootJSP JDK版本&#xff1a;JDK1.8 数据库&#xff1a;MySQL5.7 数据库工具&#xff1a;Navicat16 开发软件&#xff1a;IDEA Maven包&#xff1a;Maven3.6.3 浏览器&#xff1a;IE浏览器 功能描述 旅游信…

Hadoop-19 Flume Agent批量采集数据到HDFS集群 监听Hive的日志 操作则把记录写入到HDFS 方便后续分析

章节内容 上一节我们完成了内容&#xff1a; Flume 启动测试Flume Conf编写Flume 测试发送和接收数据 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0c;但…

深入探索大语言模型

深入探索大语言模型 引言 大语言模型&#xff08;LLM&#xff09;是现代人工智能领域中最为重要的突破之一。这些模型在自然语言处理&#xff08;NLP&#xff09;任务中展示了惊人的能力&#xff0c;从文本生成到问答系统&#xff0c;无所不包。本文将从多个角度全面介绍大语…

AGE agtype 简介

AGE 使用一种名为 agtype 的自定义数据类型&#xff0c;这是 AGE 返回的唯一数据类型。agtype 是 Json 的超集&#xff0c;也是 JsonB 的自定义实现。 简单数据类型 Null 在Cypher中&#xff0c;null用于表示缺失或未定义的值。概念上&#xff0c;null表示“缺失的未知值”&…

路径规划 | 基于蚁群算法的三维无人机航迹规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 基于蚁群算法的三维无人机航迹规划&#xff08;Matlab&#xff09;。 蚁群算法&#xff08;Ant Colony Optimization&#xff0c;ACO&#xff09;是一种模拟蚂蚁觅食行为的启发式算法。该算法通过模拟蚂蚁在寻找食物时…

【安全设备】Web应用防火墙

一、什么是Web应用防火墙 Web应用程序防火墙&#xff08;Web Application Firewall&#xff09;的缩写是WAF&#xff0c;用于保护Web应用程序免受各种恶意攻击和漏洞利用。WAF通过监控和过滤进出Web应用程序的HTTP/HTTPS流量来工作。它位于Web应用程序和用户之间&#xff0c;分…

【总线】AXI第九课时:介绍AXI响应信号 (Response Signaling):RRESP和 BRESP

大家好,欢迎来到今天的总线学习时间!如果你对电子设计、特别是FPGA和SoC设计感兴趣&#xff0c;那你绝对不能错过我们今天的主角——AXI4总线。作为ARM公司AMBA总线家族中的佼佼者&#xff0c;AXI4以其高性能和高度可扩展性&#xff0c;成为了现代电子系统中不可或缺的通信桥梁…

STM32F103RB多通道ADC转换功能实现(DMA)

目录 概述 1 硬件 1.1 硬件实物介绍 1.2 nucleo-f103rb 1.3 软件版本 2 软件实现 2.1 STM32Cube配置参数 2.2 项目代码 3 功能代码实现 3.1 ADC功能函数 3.2 函数调用 4 测试 4.1 DMA配置data width&#xff1a;byte 4.2 DMA配置data width&#xff1a;Half wor…

java如何实现一个死锁 ?

死锁(Deadlock)是指在并发系统中,两个或多个线程(或进程)因争夺资源而互相等待,导致它们都无法继续执行的一种状态。 一、简易代码 public class DeadlockExample {private static final Object lock1 = new Object();private

如何在 ASP.NET MVC 项目中使用身份验证器应用程序实现多因素身份验证?

介绍 增强安全性对于任何应用程序都至关重要&#xff0c;而多因素身份验证 (MFA) 是实现此目标的有效方法。在本文中&#xff0c;我们将介绍在 ASP.NET MVC 项目中使用身份验证器应用程序集成 MFA 的过程。无论您是从头开始还是将 MFA 添加到现有项目&#xff0c;本指南都将提…

生物素标记降钙素Biotin-α-CGRP, rat 中间体

生物素标记降钙素Biotin-α-CGRP, rat 中间体是一种特定的生物化学试剂&#xff0c;主要用于科学研究领域。以下是对该产品的详细介绍&#xff1a; 一、基本信息 产品名称&#xff1a;生物素标记降钙素Biotin-α-CGRP, rat 中间体 英文名称&#xff1a;Biotin-α-CGRP, rat 纯度…

Qt 线程同步机制 互斥锁 信号量 条件变量 读写锁

qt线程同步 Qt提供了丰富的线程同步机制来帮助开发者更高效和安全地进行多线程编程。其主要包括: QMutex:为共享数据提供互斥访问能力,避免同时写入导致的数据冲突。利用lock()/unlock()方法实现锁定和解锁。 QReadWriteLock:读写锁,允许多个读线程同时访问,但写操作需要独占…

springboot社区物资交易互助平台+lw+源码+调试+讲解

第3章 系统分析 用户的需求以及与本系统相似的在市场上存在的其它系统可以作为系统分析中参考的资料&#xff0c;分析人员可以根据这些信息确定出本系统具备的功能&#xff0c;分析出本系统具备的性能等内容。 3.1可行性分析 尽管系统是根据用户的要求进行制作&#xff0c;但…

windows USB 设备驱动开发-USB带宽

本文讨论如何仔细管理 USB 带宽的指导。 每个 USB 客户端驱动程序都有责任最大程度地减少其使用的 USB 带宽&#xff0c;并尽快将未使用的带宽返回到可用带宽池。 在这里&#xff0c;我们认为USB 2.0 的速度是480Mbps、12Mbps、1.5Mbps&#xff0c;这分别对应高速、全速、低速…

Python面试宝典第9题:买卖股票

题目 给定一个整型数组&#xff0c;它的第i个元素是一支给定股票第i天的价格。如果最多只允许完成一笔交易&#xff08;即买入和卖出一支股票一次&#xff09;&#xff0c;设计一个算法来计算你所能获取的最大利润。注意&#xff1a;你不能在买入股票前卖出股票。 示例 1&#…

LabVIEW平台从离散光子到连续光子的光子计数技术

光子计数技术用于将输入光子数转换为离散脉冲。常见的光子计数器假设光子是离散到达的&#xff0c;记录到来的每一个光子。但是&#xff0c;当两个或多个光子同时到达时&#xff0c;计数器会将其记录为单个脉冲&#xff0c;从而只计数一次。当连续光子到达时&#xff0c;离散光…

python学习-容器类型

列表 列表&#xff08;list&#xff09;是一种有序容器&#xff0c;可以向其中添加或删除任意元素. 列表数据类型是一种容器类型&#xff0c;列表中可以存放不同数据类型的值,代码示例如下&#xff1a; 列表中可以实现元素的增、删、改、查。 示例代码如下&#xff1a; 增 …

基于Unity3D的Rokid AR Glass项目开发环境搭建

初识Rokid AR 一、SDK简介二、准备工作1.软件环境2.硬件环境 三、快速接入SDK1.配置Package Manager2.安装UXR2.0 SDK 四、导入官方Demo进行模拟器测试五、Rokid AR系列教程 一、SDK简介 UXR2.0 SDK是Rokid为Unity开发者提供的AR开发工具包&#xff0c;提供空间定位跟踪、双目…