0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用Tauri CLI提供的命令生成密钥

jf_wN0SrCdH 来源:浮之静 作者:lencx 2022-10-17 10:24 次阅读

这篇文章会有一点啰嗦,我希望想把解决问题的一些思路展现出来,给遇到问题无从下手的朋友带来一些启发。

签名

Tauri 通过签名来保证安全更新应用。 签名更新应用需要做两件事:

私钥 (privkey) 用于签署应用的更新,必须严密保存。此外,如果丢失了此密钥,将无法向当前用户群发布新的更新,将其保存在安全的地方至关重要。

在 tauri.conf.json 中添加公钥 (pubkey),以在安装前验证更新存档。

生成签名

使用 Tauri CLI 提供的命令可以生成密钥(.pub 后缀的文件为公钥):

tauri signer generate -w ~/.tauri/omb.key           

$ tauri signer generate -w /Users/lencx/.tauri/omb.key
Generating new private key without password.
Please enter a password to protect the secret key.
Password: 
Password (one more time): 
Deriving a key from the password in order to encrypt the secret key... done

Your keypair was generated successfully
Private: /Users/lencx/.tauri/omb.key (Keep it secret!)
Public: /Users/lencx/.tauri/omb.key.pub
---------------------------

Environment variabled used to sign:
`TAURI_PRIVATE_KEY`  Path or String of your private key
`TAURI_KEY_PASSWORD`  Your private key password (optional)

ATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not works.
---------------------------

  Done in 39.09s.

注意:如果丢失了私钥或密码,将无法签署更新包并且更新将无法正常工作(请妥善保管)。

tauri.conf.json 配置

{
  "updater": {
    "active": true,
    "dialog": true,
    "endpoints": ["https://releases.myapp.com/{{target}}/{{current_version}}"],
    "pubkey": "YOUR_UPDATER_PUBKEY"
  },
}

active - 布尔值,是否启用,默认值为 false

dialog - 布尔值,是否启用内置新版本提示框,如果不启用,则需要在 JS 中自行监听事件并进行提醒

endpoints - 数组,通过地址列表来确定服务器端是否有可用更新,字符串 {{target}} 和 {{current_version}} 会在 URL 中自动替换。如果指定了多个地址,服务器在预期时间内未响应,更新程序将依次尝试。endpoints 支持两种格式:

动态接口[1] - 服务器根据客户端的更新请求确定是否需要更新。 如果需要更新,服务器应以状态代码 200 OK 进行响应,并在正文中包含更新 JSON。 如果不需要更新,服务器必须响应状态代码 204 No Content。

静态文件[2] - 备用更新技术使用纯 JSON 文件,将更新元数据存储在 gist[3],github-pages[4] 或其他静态文件存储中。

pubkey - 签名的公钥

实现步骤

拆解问题

要实现自动升级应用主要分为以下几个步骤:

生成签名(公私钥):

私钥用于设置打包(tauri build)的环境变量

公钥用于配置 tauri.conf.json -> updater.pubkey

向客户端推送包含签名及下载链接的更新请求,有两种形式:

动态接口返回 json 数据

静态资源返回 json 文件

将 2 中的更新请求地址配置在 tauri.conf.json -> updater.endpoints

通过将 tauri.conf.json -> updater.dialog 配置为 true,启用内置通知更新应用的弹窗。设置为 false 则需要自行通过 js 事件来处理(暂不推荐,喜欢折腾的朋友可以自行尝试)

因为应用的跨平台打包借助了 github action 的工作流来实现,具体可以参考【Tauri 入门篇 - 跨平台编译】[5],所以更新也同样使用 github action 来实现,充分发挥 github 的能力(简单来说,就是不需要借助其他第三方平台或服务就可以实现整个应用的自动化发布更新)。

梳理流程

在本地生成公私钥

加签名构建跨平台应用(通过 github action 设置签名环境变量)

对构建出的安装包解析,生成静态资源文件(通过脚本实现安装包信息获取)

推送更新请求采用静态资源的方式(可以将 json 文件存储在 github pages)

将 github pages 的资源地址配置到 tauri.conf.json -> updater.endpoints

代码实现

Step1

生成公私钥

tauri signer generate -w ~/.tauri/omb.key

配置公钥 pubkey(~/.tauri/omb.key.pub)及资源地址 endpoints(github pages 地址):

{
  "package": {
    "productName": "OhMyBox",
    "version": "../package.json"
  },
  "tauri": {
    "updater": {
      "active": true,
      "dialog": true,
      "endpoints": ["https://lencx.github.io/OhMyBox/install.json"],
      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEU5MEIwREEzNDlBNzdDN0MKUldSOGZLZEpvdzBMNmFOZ2cyY2NPeTdwK2hsV3gwcWxoZHdUWXRZWFBpQTh1dWhqWXhBdkl0cW8K"
    }
  }
}

Step2

在项目根路径下创建 scripts 目录,然后在 scripts 下依次创建 release.mjs,updatelog.mjs,updater.mjs 三个 .mjs[6] 文件:

scripts/release.mjs - 版本发布,因发布需涉及多处改动(如版本,版本日志,打 tag 标签等等),故将其写成脚本,减少记忆成本

scripts/updatelog.mjs - 版本更新日志处理,供 scripts/updater.mjs 脚本使用

scripts/updater.mjs - 生成应用更新需要的静态文件

# 安装开发依赖
yarn add -D node-fetch @actions/github
// scripts/release.mjs

import { createRequire } from 'module';
import { execSync } from 'child_process';
import fs from 'fs';

import updatelog from './updatelog.mjs';

const require = createRequire(import.meta.url);

async function release() {
  const flag = process.argv[2] ?? 'patch';
  const packageJson = require('../package.json');
  let [a, b, c] = packageJson.version.split('.').map(Number);

  if (flag === 'major') {  // 主版本
    a += 1;
    b = 0;
    c = 0;
  } else if (flag === 'minor') {  // 次版本
    b += 1;
    c = 0;
  } else if (flag === 'patch') {  // 补丁版本
    c += 1;
  } else {
    console.log(`Invalid flag "${flag}"`);
    process.exit(1);
  }

  const nextVersion = `${a}.${b}.${c}`;
  packageJson.version = nextVersion;

  const nextTag = `v${nextVersion}`;
  await updatelog(nextTag, 'release');

  // 将新版本写入 package.json 文件
  fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2));

  // 提交修改的文件,打 tag 标签(tag 标签是为了触发 github action 工作流)并推送到远程
  execSync('git add ./package.json ./UPDATE_LOG.md');
  execSync(`git commit -m "v${nextVersion}"`);
  execSync(`git tag -a v${nextVersion} -m "v${nextVersion}"`);
  execSync(`git push`);
  execSync(`git push origin v${nextVersion}`);
  console.log(`Publish Successfully...`);
}

release().catch(console.error);
// scripts/updatelog.mjs

import fs from 'fs';
import path from 'path';

const UPDATE_LOG = 'UPDATE_LOG.md';

export default function updatelog(tag, type = 'updater') {
  const reTag = /## v[d.]+/;

  const file = path.join(process.cwd(), UPDATE_LOG);

  if (!fs.existsSync(file)) {
    console.log('Could not found UPDATE_LOG.md');
    process.exit(1);
  }

  let _tag;
  const tagMap = {};
  const content = fs.readFileSync(file, { encoding: 'utf8' }).split('
');

  content.forEach((line, index) => {
    if (reTag.test(line)) {
      _tag = line.slice(3).trim();
      if (!tagMap[_tag]) {
        tagMap[_tag] = [];
        return;
      }
    }
    if (_tag) {
      tagMap[_tag].push(line);
    }
    if (reTag.test(content[index + 1])) {
      _tag = null;
    }
  });

  if (!tagMap?.[tag]) {
    console.log(
      `${type === 'release' ? '[UPDATE_LOG.md] ' : ''}Tag ${tag} does not exist`
    );
    process.exit(1);
  }

  return tagMap[tag].join('
').trim() || '';
}
// scripts/updater.mjs

import fetch from 'node-fetch';
import { getOctokit, context } from '@actions/github';
import fs from 'fs';

import updatelog from './updatelog.mjs';

const token = process.env.GITHUB_TOKEN;

async function updater() {
  if (!token) {
    console.log('GITHUB_TOKEN is required');
    process.exit(1);
  }

  // 用户名,仓库名
  const options = { owner: context.repo.owner, repo: context.repo.repo };
  const github = getOctokit(token);

  // 获取 tag
  const { data: tags } = await github.rest.repos.listTags({
    ...options,
    per_page: 10,
    page: 1,
  });

  // 过滤包含 `v` 版本信息的 tag
  const tag = tags.find((t) => t.name.startsWith('v'));
  // console.log(`${JSON.stringify(tag, null, 2)}`);

  if (!tag) return;

  // 获取此 tag 的详细信息
  const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
    ...options,
    tag: tag.name,
  });

  // 需要生成的静态 json 文件数据,根据自己的需要进行调整
  const updateData = {
    version: tag.name,
    // 使用 UPDATE_LOG.md,如果不需要版本更新日志,则将此字段置空
    notes: updatelog(tag.name),
    pub_date: new Date().toISOString(),
    platforms: {
      win64: { signature: '', url: '' }, // compatible with older formats
      linux: { signature: '', url: '' }, // compatible with older formats
      darwin: { signature: '', url: '' }, // compatible with older formats
      'darwin-aarch64': { signature: '', url: '' },
      'darwin-x86_64': { signature: '', url: '' },
      'linux-x86_64': { signature: '', url: '' },
      'windows-x86_64': { signature: '', url: '' },
      // 'windows-i686': { signature: '', url: '' }, // no supported
    },
  };

  const setAsset = async (asset, reg, platforms) => {
    let sig = '';
    if (/.sig$/.test(asset.name)) {
      sig = await getSignature(asset.browser_download_url);
    }
    platforms.forEach((platform) => {
      if (reg.test(asset.name)) {
        // 设置平台签名,检测应用更新需要验证签名
        if (sig) {
          updateData.platforms[platform].signature = sig;
          return;
        }
        // 设置下载链接
        updateData.platforms[platform].url = asset.browser_download_url;
      }
    });
  };

  const promises = latestRelease.assets.map(async (asset) => {
    // windows
    await setAsset(asset, /.msi.zip/, ['win64', 'windows-x86_64']);

    // darwin
    await setAsset(asset, /.app.tar.gz/, [
      'darwin',
      'darwin-x86_64',
      'darwin-aarch64',
    ]);

    // linux
    await setAsset(asset, /.AppImage.tar.gz/, ['linux', 'linux-x86_64']);
  });
  await Promise.allSettled(promises);

  if (!fs.existsSync('updater')) {
    fs.mkdirSync('updater');
  }

  // 将数据写入文件
  fs.writeFileSync(
    './updater/install.json',
    JSON.stringify(updateData, null, 2)
  );
  console.log('Generate updater/install.json');
}

updater().catch(console.error);

// 获取签名内容
async function getSignature(url) {
  try {
    const response = await fetch(url, {
      method: 'GET',
      headers: { 'Content-Type': 'application/octet-stream' },
    });
    return response.text();
  } catch (_) {
    return '';
  }
}

在根路径下创建 UPDATE_LOG.md 文件,通知用户更新注意事项,格式如下(使用版本号作为标题,具体请查看 scripts/updatelog.mjs):

# Updater Log

## v0.1.7

- feat: xxx
- fix: xxx

## v0.1.6

test

修改 package.json,在 "scripts" 中加入 updater 和 release 命令:

  "scripts": {
    "dev": "vite --port=4096",
    "build": "rsw build && tsc && vite build",
    "preview": "vite preview",
    "tauri": "tauri",
    "rsw": "rsw",
    "updater": "node scripts/updater.mjs", //  新增
    "release": "node scripts/release.mjs" //  新增
  },

Step3

Action 配置请参考之前的文章【Tauri 入门篇 - 跨平台编译】,此处新增环境设置签名和静态资源推送。

设置 Secret

配置变量 Repo -> Settings -> Secrets -> Actions -> New repository secret:

TAURI_PRIVATE_KEY - 私钥,value 为 ~/.tauri/omb.key.pub 内容

Name: TAURI_PRIVATE_KEY

Value: ******

TAURI_KEY_PASSWORD - 密码,value 为生成签名时的密码

Name: TAURI_KEY_PASSWORD

Value: ******

设置 .github/workflows/release.yml

name: Release CI

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:
  create-release:
    runs-on: ubuntu-latest
    outputs:
      RELEASE_UPLOAD_ID: ${{ steps.create_release.outputs.id }}

    steps:
      - uses: actions/checkout@v2
      - name: Query version number
        id: get_version
        shell: bash
        run: |
          echo "using version tag ${GITHUB_REF:10}"
          echo ::set-output name=version::"${GITHUB_REF:10}"

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: '${{ steps.get_version.outputs.VERSION }}'
          release_name: 'OhMyBox ${{ steps.get_version.outputs.VERSION }}'
          body: 'See the assets to download this version and install.'

  build-tauri:
    needs: create-release
    strategy:
      fail-fast: false
      matrix:
        platform: [macos-latest, ubuntu-latest, windows-latest]

    runs-on: ${{ matrix.platform }}
    steps:
      - uses: actions/checkout@v2

      - name: Setup node
        uses: actions/setup-node@v1
        with:
          node-version: 16

      - name: Install Rust stable
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable

      # Rust cache
      - uses: Swatinem/rust-cache@v1

      - name: install dependencies (ubuntu only)
        if: matrix.platform == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf

      # Install wasm-pack
      - uses: jetli/wasm-pack-action@v0.3.0
        with:
          # Optional version of wasm-pack to install(eg. 'v0.9.1', 'latest')
          version: v0.9.1

      - name: Install rsw
        run: cargo install rsw

      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn config get cacheFolder)"

      - name: Yarn cache
        uses: actions/cache@v2
        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-

      - name: Install app dependencies and build it
        run: yarn && yarn build
      - uses: tauri-apps/tauri-action@v0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
          TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
        with:
          releaseId: ${{ needs.create-release.outputs.RELEASE_UPLOAD_ID }}

  # 生成静态资源并将其推送到 github pages
  updater:
    runs-on: ubuntu-latest
    needs: [create-release, build-tauri]

    steps:
      - uses: actions/checkout@v2
      - run: yarn
      - run: yarn updater
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy install.json
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./updater
          force_orphan: true

发布应用

功能开发完成,提交代码后,只需执行 yarn release 命令就可以自动进行应用发布了。如果不想借助 github 打包和静态资源存放,也可以参考上面的步骤,自行部署。

# 发布主版本,v1.x.x -> v2.x.x
yarn release --major

# 发布次版本,v1.0.x -> v1.1.x
yarn release --minor

# 发布补丁版本,patch 参数可省略,v1.0.0 -> v1.0.1
yarn release [--patch]

注意:每次执行 yarn release 发布版本,主版本,次版本,补丁版本 都是自增 1。

3c743792-4c9f-11ed-a3b6-dac502259ad0.png3d225052-4c9f-11ed-a3b6-dac502259ad0.png

常见问题

Error A public key has been found, but no private key

如果在 tauri.conf.json 中配置了 pubkey,但未设置环境变量会出现以下错误:

tauri build
# ...
   Compiling omb v0.1.0 (/Users/lencx/github/lencx/OhMyBox/src-tauri)
    Finished release [optimized] target(s) in 21.27s
    Bundling OhMyBox.app (/Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app)
    Bundling OhMyBox_0.1.1_x64.dmg (/Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/dmg/OhMyBox_0.1.1_x64.dmg)
     Running bundle_dmg.sh
    Bundling /Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app.tar.gz (/Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app.tar.gz)
    Finished 3 bundles at:
        /Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app
        /Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/dmg/OhMyBox_0.1.1_x64.dmg
        /Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app.tar.gz (updater)

       Error A public key has been found, but no private key. Make sure to set `TAURI_PRIVATE_KEY` environment variable.
error Command failed with exit code 1.

解决方案:

Use environment variables in Terminal on Mac[7]

Set Environment Variable in Windows[8]

# macOS 设置环境变量:
export TAURI_PRIVATE_KEY="********" # omb.key
export TAURI_KEY_PASSWORD="********" # 生成公私钥时在终端输入的密码,如果未设置密码则无需设置此变量

# Windows 设置环境变量:
set TAURI_PRIVATE_KEY="********"
set TAURI_KEY_PASSWORD="********"
# 如果签名打包成功会看到以下信息(以 macOS 为例)
        Info 1 updater archive at:
        Info         /Users/lencx/github/lencx/OhMyBox/src-tauri/target/release/bundle/macos/OhMyBox.app.tar.gz.sig
  Done in 58.55s.

版本信息错误

发布的应用版本以 tauri.conf.json 中的 package.version 为准,在发布新版本时注意更新 version。

可能造成更新失败的原因

使用 github pages 作为更新文件静态资源存储在国内会因网络限制导致更新失败,无法看到更新弹窗提示,或者下载不响应等问题,可以通过配置多个 endpoints 地址来解决,安装包也可以放在自建服务器来提高下载的稳定性

静态 json 文件中的平台签名(platforms[platform].signature)是否完整,签名内容可以在tauri build 产生的 target/release/bundle//*.sig 文件中查看

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 密钥
    +关注

    关注

    1

    文章

    137

    浏览量

    19747
  • 命令
    +关注

    关注

    5

    文章

    681

    浏览量

    22008
  • 代码
    +关注

    关注

    30

    文章

    4766

    浏览量

    68458

原文标题:Tauri 应用篇 - 自动通知应用升级

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【MiCOKit试用体验】+ cli命令行简单分析

    不知道怎么了,网站10月初数据崩溃了,,这个帖子也没找回来,,没办法,智能再来一贴了,,,前面几贴简单介绍了入门,同时说明了如何使用mico的库来开发驱动程序,这节来讨论下mico的命令行功能CLI
    发表于 10-17 19:13

    【MiCOKit试用体验】+ 如何扩展MICO中的cli命令

    一些内建命令的定义,当然并不是所有功能和内容都在这,还有一些通过二进制链接库提供,估计是保全版权吧,给闭源了,在这里不多说了,大家要想仔细分析源码,学学技巧呢,自己研究哦。 这里说一下cli的内置
    发表于 11-08 19:42

    如何安装和升级了AWS CLI

    AWS CLI。在CMD提示和GT;AWS配置中键入之后,我按要求输入了访问密钥ID和访问密钥。在README.md指令之后,它要求在终端窗口中运行以下命令。>aws iot.-end
    发表于 04-29 07:57

    STM32_Programmer_CLI有关闭设备的特定命令吗?

    0x9ffd3d2f设置 为字 24 (0x18) [ pkh0 ]STM32_Programmer_CLI -c port=usb1 -otp program wordID=0x18 value=0x9ffd3d2f这是正确的吗?STM32_Programmer_CLI
    发表于 01-29 07:13

    基于灰色半解生成密钥分存方案

    对灰色半解生成算法进行研究,提出基于灰色半解生成密钥分存方案。该方案只需密钥分配者随机产生一正整数集合,利用灰色半生成算法得出其半解
    发表于 04-11 09:38 6次下载

    基于混沌序列的种子密钥生成方法

    本文提出一种基于混沌动力学模型的加密算法种子密钥生成方法。该方法通过扩展Tent 映射生成混沌序列,选取二值化后序列一段数据构造安全算法的种子密钥表。实验表明,
    发表于 09-02 08:21 19次下载

    赛灵思研发提供生成独特的器件“指纹码”的密钥加密密钥

    赛灵思的最新 PUF IP 由 Verayo 提供,能生成独特的器件“指纹码”,也就是只有器件自己知道的具有强大加密功能的密钥加密密钥(KEK)。PUF 利用 CMOS 制造工艺变量优
    的头像 发表于 07-30 09:22 2709次阅读

    芯片AES加密密钥生成工具

    芯片AES加密密钥生成工具前言:嵌入式单片机开发,为了防止别人将芯片内的代码读取出来通过反编译手段拿到源码,常用的手段是对芯片和烧录文件进行加密。大部分的芯片厂商都会提供一个加密烧录和配置文件的工具
    发表于 12-09 14:36 6次下载
    芯片AES加密<b class='flag-5'>密钥</b><b class='flag-5'>生成</b>工具

    Anyshortcut-cli Rust编写的命令行工具

    ./oschina_soft/anyshortcut-cli.zip
    发表于 05-26 15:48 0次下载
    Anyshortcut-<b class='flag-5'>cli</b> Rust编写的<b class='flag-5'>命令</b>行工具

    存储密钥与文件加密密钥介绍

    可信应用的存储密钥 可信应用的存储密钥(Trusted Applicant Storage Key, TSK)是生成FEK时使用到的密钥。 TSK是使用SSK作为
    的头像 发表于 11-21 11:43 1270次阅读
    存储<b class='flag-5'>密钥</b>与文件加密<b class='flag-5'>密钥</b>介绍

    怎么用SSH密钥登陆vps?

    生成SSH密钥对(在本地机器上执行) 1、打开终端(命令行界面)。 2、输入以下命令生成SSH密钥
    的头像 发表于 02-20 16:29 1114次阅读

    鸿蒙开发:Universal Keystore Kit密钥管理服务 密钥生成介绍及算法规格

    当业务需要使用HUKS生成随机密钥,并由HUKS进行安全保存时,可以调用HUKS的接口生成密钥
    的头像 发表于 07-04 21:50 334次阅读
    鸿蒙开发:Universal Keystore Kit<b class='flag-5'>密钥</b>管理服务 <b class='flag-5'>密钥</b><b class='flag-5'>生成</b>介绍及算法规格

    鸿蒙开发:Universal Keystore Kit密钥管理服务 生成密钥ArkTS

    生成DH密钥为例,生成随机密钥。具体的场景介绍及支持的算法规格
    的头像 发表于 07-05 15:17 309次阅读
    鸿蒙开发:Universal Keystore Kit<b class='flag-5'>密钥</b>管理服务 <b class='flag-5'>生成</b><b class='flag-5'>密钥</b>ArkTS

    鸿蒙开发:Universal Keystore Kit密钥管理服务 生成密钥C、C++

    生成ECC密钥为例,生成随机密钥。具体的场景介绍及支持的算法规格。
    的头像 发表于 07-06 10:48 1122次阅读
    鸿蒙开发:Universal Keystore Kit<b class='flag-5'>密钥</b>管理服务 <b class='flag-5'>生成</b><b class='flag-5'>密钥</b>C、C++

    TMP1827 的 密钥生成和身份验证机制

    电子发烧友网站提供《TMP1827 的 密钥生成和身份验证机制.pdf》资料免费下载
    发表于 09-09 09:24 0次下载
    TMP1827 的 <b class='flag-5'>密钥</b><b class='flag-5'>生成</b>和身份验证机制