鸿蒙HarmonyOS编程开发:TLS单向认证通讯示例

2024-08-23 21:36

本文主要是介绍鸿蒙HarmonyOS编程开发:TLS单向认证通讯示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.TLS简介

TLS(Transport Layer Security)协议的前身是SSL(Secure Socket Layer)安全套接层协议,由Netscape公司于1994年提出,是一套网络通信安全协议。IETF(The Internet Engineering Task Force)后期负责SSL协议,并且重新命名为TLS协议。IETF于1999年发布了TLS 1.0版本,该版本基于SSL 3.0;2006年4月,发布了TLS 1.1版本,2008年8月,发布了TLS 1.2版本,2018年3月,TLS 1.3版本发布,是目前最新的TLS版本。

2. TLS的常用方法

鸿蒙封装的TLS操作类位于模块socket中,使用如下的方式导入:

import socket from '@ohos.net.socket';

        socket模块包括了众多的TCP操作方法,就本文而言,重点需要掌握的是如下五个:

1)constructTLSSocketInstance(): TLSSocket

创建并返回一个TLSSocket对象,,在使用TLSSocket的方法以前需要创建该对象。

2)bind(address: NetAddress): Promise<void>

绑定IP地址和端口,端口可以指定或由系统随机分配,可以使用0.0.0.0表示本机IP地址;使用Promise方式作为异步方法。

3)connect(options: TLSConnectOptions): Promise<void>

连接到指定的TLS服务端,参数options包含了连接的地址address、TLS安全配置secureOptions以及ALPN协议列表ALPNProtocols,其中address和secureOptions是必选的,ALPN是可选的,使用promise方法作为异步方法。

4)send(data: string): Promise<void>

通过TLSSocket连接向服务端发送消息data,使用Promise方式作为异步方法。

5)on(type: 'message', callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void

订阅TLSSocket连接的接收消息事件,当套接字接收到消息时触发该事件,其中message表示接收到的消息,remoteInfo是发送方信息;使用callback方式作为异步方法。

3. TLS单向认证通讯示例

为演示TLS安全通讯单向认证的方式(即客户端认证服务端,客户端本身不提供证书),本示例实现了使用TLS协议发送、接收消息的功能,运行后的初始界面如下所示:

cke_115807.jpeg

本示例中,可以配置TLS服务端的地址,可以直接输入服务端证书的CA信息,或者从文件加载,在配置好CA后,就可以连接服务端了,连接握手成功后,就可以发送信息给对方。

下面详细介绍创建该应用的步骤。

步骤1:创建Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [

      {

        "name": "ohos.permission.INTERNET"

      },

      {

        "name": "ohos.permission.GET_WIFI_INFO"

      }

    ]

这里分别添加了访问互联网和访问WIFI信息的权限。

步骤3:在Index.ets文件里添加如下的代码:

import socket from '@ohos.net.socket';
import wifiManager from '@ohos.wifiManager';
import systemDateTime from '@ohos.systemDateTime';
import util from '@ohos.util';
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import common from '@ohos.app.ability.common';//执行TLS通讯的对象
let tlsSocket = socket.constructTLSSocketInstance()//说明:本地的IP地址不是必须知道的,绑定时绑定到IP:0.0.0.0即可,显示本地IP地址的目的是方便对方发送信息过来
//本地IP的数值形式
let ipNum = wifiManager.getIpInfo().ipAddress
//本地IP的字符串形式
let localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);let caFileUri = ''@Entry
@Component
struct Index {//连接、通讯历史记录@State msgHistory: string = ''//要发送的信息@State sendMsg: string = ''//服务端IP地址@State serverIp: string = "0.0.0.0"//服务端端口@State serverPort: number = 9999//是否可以加载@State canLoad: boolean = false//是否可以连接@State canConnect: boolean = false//是否可以发送消息@State canSend: boolean = false@State ca: string = ``scroller: Scroller = new Scroller()build() {Row() {Column() {Text("TLS通讯示例").fontSize(14).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.Center).padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("本地IP地址:").width(100).fontSize(14).flexGrow(0)Text(localIp).width(110).fontSize(12).flexGrow(1)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("服务端地址:").fontSize(14).width(90).flexGrow(1)TextInput({ text: this.serverIp }).onChange((value) => {this.serverIp = value}).width(110).fontSize(12).flexGrow(4)Text(":").width(5).flexGrow(0)TextInput({ text: this.serverPort.toString() }).type(InputType.Number).onChange((value) => {this.serverPort = parseInt(value)}).fontSize(12).flexGrow(2).width(50)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("CA(输入或者加载)").fontSize(14).width(90).flexGrow(1)Button("选择").onClick(() => {this.selectCA()}).width(70).fontSize(14).flexGrow(0)Button("加载").onClick(() => {this.loadCA()}).enabled(this.canLoad).width(70).fontSize(14).flexGrow(0)Button("连接").onClick(() => {this.connect2Server()}).enabled(this.canConnect).width(70).fontSize(14).flexGrow(0)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {TextArea({ text: this.ca }).onChange((value) => {this.ca = value}).flexGrow(1).height(200)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {TextInput({ placeholder: "输入要发送的消息" }).onChange((value) => {this.sendMsg = value}).width(200).flexGrow(1)Button("发送").enabled(this.canSend).width(70).fontSize(14).flexGrow(0).onClick(() => {this.sendMsg2Server()})}.width('100%').padding(10)Scroll(this.scroller) {Text(this.msgHistory).textAlign(TextAlign.Start).padding(10).width('100%').backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(300).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width('100%').justifyContent(FlexAlign.Start).height('100%')}.height('100%')}//发送消息到服务端sendMsg2Server() {tlsSocket.send(this.sendMsg + "\r\n").then(async () => {this.msgHistory += "我:" + this.sendMsg + await getCurrentTimeString() + "\r\n"}).catch((e) => {this.msgHistory += '发送失败' + e.message + "\r\n";})}//绑定本地地址async bind2LocalAddress() {//本地地址let localAddress = { address: "0.0.0.0", family: 1 }await tlsSocket.bind(localAddress).then(() => {this.msgHistory = 'bind success' + "\r\n";}).catch((e) => {this.msgHistory = 'bind fail ' + e.message + "\r\n";})//收到消息时的处理tlsSocket.off("message")tlsSocket.on("message", async (value) => {let msg = buf2String(value.message)let time = await getCurrentTimeString()this.msgHistory += "服务端:" + msg + time + "\r\n"this.scroller.scrollEdge(Edge.Bottom)})}//选择CA证书文件selectCA() {let documentPicker = new picker.DocumentViewPicker();documentPicker.select().then((result) => {if (result.length > 0) {caFileUri = result[0]this.msgHistory += "select file: " + caFileUri + "\r\n";this.canLoad = true}}).catch((e) => {this.msgHistory += 'DocumentViewPicker.select failed ' + e.message + "\r\n";});}//加载CA文件内容loadCA() {try {let buf = new ArrayBuffer(1024 * 4);let file = fs.openSync(caFileUri, fs.OpenMode.READ_ONLY);let readLen = fs.readSync(file.fd, buf, { offset: 0 });this.ca = buf2String(buf.slice(0, readLen))this.canConnect = truefs.closeSync(file);}catch (e) {this.msgHistory += 'readText failed ' + e.message + "\r\n";}}//连接服务端connect2Server() {//绑定本地地址this.bind2LocalAddress()//服务端地址let serverAddress = { address: this.serverIp, port: this.serverPort, family: 1 }let opt: socket.TLSSecureOptions = {ca: [this.ca]}tlsSocket.connect({ address: serverAddress, secureOptions: opt }).then(() => {this.msgHistory = 'connect success ' + "\r\n";this.canSend = true}).catch((e) => {this.msgHistory = 'connect fail ' + e.message + "\r\n";})}
}//同步获取当前时间的字符串形式
async function getCurrentTimeString() {let time = ""await systemDateTime.getDate().then((date) => {time = date.getHours().toString() + ":" + date.getMinutes().toString()+ ":" + date.getSeconds().toString()})return "[" + time + "]"
}//ArrayBuffer转utf8字符串
function buf2String(buf: ArrayBuffer) {let msgArray = new Uint8Array(buf);let textDecoder = util.TextDecoder.create("utf-8");return textDecoder.decodeWithStream(msgArray)
}复制

步骤4:编译运行,可以使用模拟器或者真机。

步骤5:配置CA信息,单击“选择”按钮选择CA证书,如图所示:

cke_654546.jpeg

步骤6:单击“加载”按钮加载CA证书,如图所示:

cke_679681.jpeg

步骤7:配置服务端地址,当前,前提是要运行一个TLS服务端,具体的服务端可以使用别的语言编写,或者使用更高版本的鸿蒙API编写,本例假定使用一个基于TLS的回声服务器,配置好后,单击“连接”按钮即可开始连接服务端。连接成功后,如果在服务端监听,可以看到如下的连接过程信息:

cke_1097373.jpg

步骤8:输入要发送的信息,单击“发送”按钮即可发送信息到服务端,如下图所示:

cke_1338959.jpeg

如果监听发送接收消息,可以看到Application Data的发送过程:

cke_1424014.jpg

通过上面的过程可知,在经过成功的握手后,消息发送接收都是基于密文的,达到了保密的目的。

这样就完成了一个简单的TLS单向认证消息发送应用。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

  →【纯血版鸿蒙全套最新学习资料】希望这一份鸿蒙学习资料能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习资料+学习PDF文档

HarmonyOS Next 最新全套视频教程

  纯血版鸿蒙全套学习资料(面试、文档、全套视频等)              

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

这篇关于鸿蒙HarmonyOS编程开发:TLS单向认证通讯示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1100551

相关文章

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

在Pandas中进行数据重命名的方法示例

《在Pandas中进行数据重命名的方法示例》Pandas作为Python中最流行的数据处理库,提供了强大的数据操作功能,其中数据重命名是常见且基础的操作之一,本文将通过简洁明了的讲解和丰富的代码示例,... 目录一、引言二、Pandas rename方法简介三、列名重命名3.1 使用字典进行列名重命名3.编

Python使用Colorama库美化终端输出的操作示例

《Python使用Colorama库美化终端输出的操作示例》在开发命令行工具或调试程序时,我们可能会希望通过颜色来区分重要信息,比如警告、错误、提示等,而Colorama是一个简单易用的Python库... 目录python Colorama 库详解:终端输出美化的神器1. Colorama 是什么?2.

Go Gorm 示例详解

《GoGorm示例详解》Gorm是一款高性能的GolangORM库,便于开发人员提高效率,本文介绍了Gorm的基本概念、数据库连接、基本操作(创建表、新增记录、查询记录、修改记录、删除记录)等,本... 目录1. 概念2. 数据库连接2.1 安装依赖2.2 连接数据库3. 数据库基本操作3.1 创建表(表关

Python视频剪辑合并操作的实现示例

《Python视频剪辑合并操作的实现示例》很多人在创作视频时都需要进行剪辑,本文主要介绍了Python视频剪辑合并操作的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录介绍安装FFmpegWindowsMACOS安装MoviePy剪切视频合并视频转换视频结论介绍

python多进程实现数据共享的示例代码

《python多进程实现数据共享的示例代码》本文介绍了Python中多进程实现数据共享的方法,包括使用multiprocessing模块和manager模块这两种方法,具有一定的参考价值,感兴趣的可以... 目录背景进程、进程创建进程间通信 进程间共享数据共享list实践背景 安卓ui自动化框架,使用的是