鸿蒙双向认证

embedded/2024/9/23 14:23:56/

鸿蒙双向认证

开发环境 基于API12

参考文档

切换到鸿蒙也要用上双向认证。使用的其中的 rcp 功能,详细文档https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/remote-communication-rcp-V5

双向认证包含两个方向,分为客户端验证服务端的证书和服务端验证客户端的证书。

客户端验证服务端的证书

这个就需要把服务端的证书内置在客户端里边,并且在请求的时候获取到服务端的证书,然后自己进行对比证书是否同内置的一样。

服务器证书的校验等级有以下几种:

  1. DefaultTrustEvaluator,使用默认的验证方式,验证证书的有效性,证书信任链那套
  2. RevocationTrustEvaluator,验证证书是否被吊销
  3. PinnedCertificatesTrustEvaluator,验证证书是否同本地的一致,可以是自签证书
  4. PublicKeysTrustEvaluator,验证证书的公钥,可以是自签证书,不过这个有个好处就是不用关心证书的有效期了
  5. CompositeTrustEvaluator,混合模式
  6. DisabledTrustEvaluator,不验证证书

可以按需自己处理。本文以对比公钥为例。

首先获取本地证书及证书的公钥。

let context = getContext(this)
const getRawFileContent = (ctx: Context, file: string) : string => {let buffer = ctx.resourceManager.getRawFileContentSync(file).bufferreturn String.fromCharCode(...new Uint8Array(buffer))
}function stringToUint8Array(str: string): Uint8Array {let arr: Array<number> = [];for (let i = 0, j = str.length; i < j; i++) {arr.push(str.charCodeAt(i));}return new Uint8Array(arr);
}const uInt8ToString = (buffer: Uint8Array): string => {return String.fromCharCode(...new Uint8Array(buffer))
}let serverCert: cert.X509Cert | null = null
let serverCertStr: string | null = nullcert.createX509Cert({data: stringToUint8Array(getRawFileContent(context, 'server.cer')),encodingFormat: cert.EncodingFormat.FORMAT_DER
}).then(x509Cert => {serverCert = x509CertserverCertStr = uInt8ToString(serverCert?.getPublicKey().getEncoded().data)
}).catch((error: BusinessError) => {
})

增加自定义验证证书函数。对比公钥是否一致。

{security: {remoteValidation: (context: rcp.ValidationContext) => {let tar = uInt8ToString(context.x509Certs[0].getPublicKey().getEncoded().data)if (serverCertStr === tar) {return true}return false},},
}

这样客户端就验证了服务端证书是否符合要求。

服务端验证客户端的证书

由于接口请求的问题,需要把客户端证书写入到沙盒里边,然后把沙盒地址传进去,就有点麻烦。

首先写入客户端证书到沙盒。

本文需要使用到crt及key两个文件。接口crt文件需要文本形式,但是key又需要沙盒地址。

const getRawFileContent = (ctx: Context, file: string) : string => {let buffer = ctx.resourceManager.getRawFileContentSync(file).bufferreturn String.fromCharCode(...new Uint8Array(buffer))
}let context = getContext(this)
let filesDir = context.filesDirfunction saveFile(fn: string) {let file = fs.openSync(filesDir + '/' + fn, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)let clientContent = context.resourceManager.getRawFileContentSync(fn)fs.writeSync(file.fd, clientContent.buffer)fs.fsyncSync(file.fd)fs.closeSync(file)
}saveFile('client.key')

然后提供客户端证书给服务端进行校验。

{security: {certificate: {content: getRawFileContent(context, 'client.crt'),key: filesDir + '/client.key',type: 'PEM',keyPassword: 'xxx'},},
}

这样就能把证书提供给服务端进行校验了。

完整实例

import { BusinessError } from '@ohos.base';
import { rcp } from "@kit.RemoteCommunicationKit";
import fs from '@ohos.file.fs';
import { cert } from '@kit.DeviceCertificateKit';
import { cryptoFramework } from '@kit.CryptoArchitectureKit';const getRawFileContent = (ctx: Context, file: string) : string => {let buffer = ctx.resourceManager.getRawFileContentSync(file).bufferreturn String.fromCharCode(...new Uint8Array(buffer))
}let context = getContext(this)
let filesDir = context.filesDirfunction saveFile(fn: string) {let file = fs.openSync(filesDir + '/' + fn, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)let clientContent = context.resourceManager.getRawFileContentSync(fn)fs.writeSync(file.fd, clientContent.buffer)fs.fsyncSync(file.fd)fs.closeSync(file)
}saveFile('client.key')function stringToUint8Array(str: string): Uint8Array {let arr: Array<number> = [];for (let i = 0, j = str.length; i < j; i++) {arr.push(str.charCodeAt(i));}return new Uint8Array(arr);
}const uInt8ToString = (buffer: Uint8Array): string => {return String.fromCharCode(...new Uint8Array(buffer))
}let serverCert: cert.X509Cert | null = null
let serverCertStr: string | null = nullcert.createX509Cert({data: stringToUint8Array(getRawFileContent(context, 'server.cer')),encodingFormat: cert.EncodingFormat.FORMAT_DER
}).then(x509Cert => {serverCert = x509CertserverCertStr = uInt8ToString(serverCert?.getPublicKey().getEncoded().data)
}).catch((error: BusinessError) => {console.error('createX509Cert failed, errCode: ' + error.code + ', errMsg: ' + error.message);
})const defaultTimeout: number = 60*1000const createRequestConfiguration = (timeout: number): rcp.Configuration => {return {security: {remoteValidation: (context: rcp.ValidationContext) => {let tar = uInt8ToString(context.x509Certs[0].getPublicKey().getEncoded().data)if (serverCertStr === tar) {return true}return false},certificate: {content: getRawFileContent(context, 'client.crt'),key: filesDir + '/client.key',type: 'PEM',keyPassword: 'xxx'},},transfer: {autoRedirect: true,timeout: {connectMs: 5000,transferMs: timeout,}}}
}const sessionConfig: rcp.SessionConfiguration = {requestConfiguration: createRequestConfiguration(defaultTimeout)
}const session: rcp.Session = rcp.createSession(sessionConfig)export const rcpget = (url:string, timeout: number = defaultTimeout):Promise<object> => {return new Promise((resolve, reject) => {let request = new rcp.Request(url, 'GET', getHeaders())if (timeout != defaultTimeout) {request.configuration = createRequestConfiguration(timeout)}session.fetch(request).then((response:rcp.Response) => {if (response.statusCode == 200) {resolve(data)} else {reject()}}).catch((err: BusinessError) => {reject()})})
}export const rcppost = (url: string, params: Record<string, string | number>, timeout: number = defaultTimeout):Promise<object> => {let p: string[] = []for(let kv of Object.entries(params)) {p.push(`${kv[0]}=${kv[1]}`)}let pstr: string = p.join('&')return new Promise((resolve, reject) => {let request: rcp.Requestif (pstr == '') {request = new rcp.Request(url, 'POST', getHeaders())} else {request = new rcp.Request(url, 'POST', getHeaders(), pstr)}if (timeout != defaultTimeout) {request.configuration = createRequestConfiguration(timeout)}session.fetch(request).then((response:rcp.Response) => {if (response.statusCode == 200) {resolve(data)} else {reject()}}).catch((err: BusinessError) => {reject()})})
}

如此这般就能实现双向认证。感觉安全级别又上了一个等级。


http://www.ppmy.cn/embedded/108530.html

相关文章

10,sql约束(2)

MySQL中primary key和unique的区别 总体而言&#xff0c;主键用于唯一标识表中的每一行记录&#xff0c;而Unique key用于确保某列或列组合的值在表中是唯一的&#xff0c;但它不一定是用来标识记录的主要手段 在sql、oracle中的constrain有两种约束&#xff0c;都是对列的唯一…

OpenCV结构分析与形状描述符(8)点集凸包计算函数convexHull()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 查找一个点集的凸包。 函数 cv::convexHull 使用斯克拉斯基算法&#xff08;Sklansky’s algorithm&#xff09;来查找一个二维点集的凸包&#…

golang hertz框架入门

两种模式新建项目 1、手动新建项目 2、使用hz工具新建项目 一、手动创建项目&#xff0c;并拉取框架 1、新建项目目录 hertz_demo_w 2、在项目跟目录新建main.go 文件 package mainimport ("context""github.com/cloudwego/hertz/pkg/app""github.…

微软发布Phi-3.5 SLM,附免费申请试用

Phi-3 模型系列是Microsoft 小型语言模型 (SLM) 系列中的最新产品。 它们旨在具有高性能和高性价比&#xff0c;在语言、推理、编码和数学等各种基准测试中的表现均优于同类和更大规模的模型。Phi-3 模型的推出扩大了 Azure 客户的高质量模型选择范围&#xff0c;为他们编写和…

分类评价指标

分类算法的评价指标用于衡量模型在分类任务中的表现&#xff0c;帮助判断模型的好坏和适用性。以下是常用的分类评价指标&#xff1a; 1. 准确率 (Accuracy) 定义: 正确分类的样本数占总样本数的比例。公式: \[ \text{Accuracy} \frac{TP TN}{TP TN FP FN} \]适用场景: …

iOS——atomic、nonatomic、assign、_unsafe_unretain

atomic和nonatomic 在iOS开发中&#xff0c;当你定义一个属性时&#xff0c;编译器会自动为你生成一个带下划线的成员变量&#xff08;实例变量&#xff09;以及对应的getter和setter方法。如果你使用atomic修饰这个属性&#xff0c;那么编译器在生成setter和getter方法时&…

网络安全基础—加解密原理与数字证书

目录 1&#xff09; 对称加密和非对称加密 Ⅰ 对称加密算法 Ⅱ 非对称加密算法 Ⅲ 对称和非对称加密比较: 2&#xff09;数据加密--数字信封 3&#xff09;数据验证 - 数字签名 4&#xff09;数字证书 Ⅰ 数字证书格式 Ⅱ 证书的颁发 Ⅲ 证书验证&#xff1a; .验证…

Docker编译环境的使用(ubuntu)

目录 Ubuntu安装docker 重启docker 拉取镜像 进入docker安装软件 提交docker 添加用户到docker组 进入docker 添加build用户 停止容器 保存docker镜像 load镜像 删除容器 Ubuntu安装docker sudo apt install docker.io 国内可用的源 Welcome to nginx! (tence…