当前位置: 首页 > news >正文

鸿蒙网络编程系列7-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协议发送、接收消息的功能,运行后的初始界面如下所示:

本示例中,可以配置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证书,如图所示:

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

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

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

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

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

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

(本文作者原创,除非明确授权禁止转载)

本文码云源码地址: https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/tls/TlsDemo

本系列码云源码地址:https://gitee.com/zl3624/harmonyos_network_samples

相关文章:

鸿蒙网络编程系列7-TLS安全数据传输单向认证示例

1.TLS简介 TLS&#xff08;Transport Layer Security&#xff09;协议的前身是SSL&#xff08;Secure Socket Layer&#xff09;安全套接层协议&#xff0c;由Netscape公司于1994年提出&#xff0c;是一套网络通信安全协议。IETF&#xff08;The Internet Engineering Task Fo…...

LangGraph 源码分析 | BaseTool 模板类

文章目录 BaseTool 源码分析核心属性以 TavilySearchResults(BaseTool) 为例namedescriptionargs_schemaresponse_format查询选项属性 需要子类实现的抽象方法以 TavilySearchResults(BaseTool) 为例 核心方法arun()&#xff1a;run()的异步执行版本invoke()和ainvoke() BaseTo…...

vulnhub靶场之JOY

一.环境搭建 1.靶场描述 Does penetration testing spark joy? If it does, this machine is for you. This machine is full of services, full of fun, but how many ways are there to align the stars? Perhaps, just like the child in all of us, we may find joy in …...

intel和AMD突然联姻,这操作给我看傻了

要说现在的显卡一哥&#xff0c;那肯定非 NVIDIA 莫属&#xff0c;不仅仅是在 AI 领域是赚的盆满钵满&#xff0c;更是在游戏显卡领域把红蓝两家打的节节败退。 在 6000 系列尚能与之一战的 AMD 也认清了现实&#xff0c;在最近宣布了下一代 8000 系列显卡放弃高端显卡战争&…...

yolo_face_pose-DataBall 人脸关键点数据集 >> DataBall

数据集下载地址&#xff1a;ultralyticsyolo训练自定义人脸关键点训练和验证数据集资源-CSDN文库 数据集定义&#xff1a; ultralytics yolo 训练自定义人脸关键点训练和验证数据集 数据集格式&#xff1a;yolo 训练集数量&#xff1a;3295 验证集数量&#xff1a;120 类别&a…...

Unity 山水树木

本章节内容 1. Unity对3D游戏物体的简单操作&#xff1b; 2. 构建山水树木的场景 1. Unity 简易操作 1.1 新建3D游戏场景 1. 打开Unity Hub&#xff0c;点击 New Project &#xff08;新建项目&#xff09;按键&#xff0c;选择第二项 3D(Built-In Render Pipeline)&#xf…...

Redis 性能优化选择:Pika 的配置与使用详解

引言 在我们日常开发中 redis是我们开发业务场景中不可缺少的部分。Redis 凭借其内存存储和快速响应的特点&#xff0c;广泛应用于缓存、消息队列等各种业务场景。然而&#xff0c;随着数据量的不断增长&#xff0c;单节点的 Redis 因为内存限制和并发能力的局限&#xff0c;逐…...

【某农业大学计算机网络实验报告】实验三 IP数据报发送和转发流程

实验目的&#xff1a; &#xff08;1&#xff09;掌握基本的网络配置方法。 &#xff08;2&#xff09;观察 IP 数据报的发送和转发流程&#xff0c;掌握 IP 转发分组的原理。 实验器材&#xff1a; 一台Windows操作系统的PC机。 实验准备&#xff1a; 1&#xff0e;配置…...

Android13 添加运行时权限

在一些场景下&#xff0c;需要给app 添加运行时权限&#xff0c;这样就不需要在使用的时候再去点击授权。 直接上代码&#xff1a; --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.javab/services/core/java/com/android/server/pm…...

官方操刀占用仅6G,Win 11 LTSC详细安装、优化教程来了

前段时间微软发布 Win 11 年度重磅更新 24H2&#xff0c;顺便也带来了备受期待的 Win 11 2024 官方精简 LTSC&#xff08;老坛酸菜&#xff09;版。 Win 11 重磅更新发布&#xff0c;老坛酸菜版成了配角&#xff01; 简单来说&#xff0c;Win 11 LTSC 是微软针对企业用户推出…...

【论文精读】RELIEF: Reinforcement Learning Empowered Graph Feature Prompt Tuning

RELIEF: Reinforcement Learning Empowered Graph Feature Prompt Tuning 前言AbstractMotivationSolutionRELIEFIncorporating Feature Prompts as MDPAction SpaceState TransitionReward Function Policy Network ArchitectureDiscrete ActorContinuous ActorCritic Overall…...

2023-06 GESP C++三级试卷

2023-06 GESP C三级试卷 &#xff08;满分&#xff1a;100 分 考试时间&#xff1a;90 分钟&#xff09; PDF试卷及答案回复:GESPC2023063 一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 1 高级语言编写的程序需要经过以下&#xff08; &#xff09;操…...

Maven--简略

简介 Apache旗下的一款开源项目&#xff0c;用来进行项目构建&#xff0c;帮助开发者管理项目中的jar及jar包之间的依赖&#xff0c;还拥有项目编译、测试、打包的功能。 管理方式 统一建立一个jar仓库&#xff0c;把jar上传至统一的仓库&#xff0c;使用时&#xff0c;配置…...

leetcode 刷题day44动态规划Part13( 647. 回文子串、516.最长回文子序列)

647. 回文子串 动规五部曲&#xff1a; 1、确定dp数组&#xff08;dp table&#xff09;以及下标的含义 按照之前做题的惯性&#xff0c;定义dp数组的时候很自然就会想题目求什么&#xff0c;就如何定义dp数组。但是对于本题来说&#xff0c;这样定义很难得到递推关系&#x…...

华为OD机试真题---关联子串

华为OD机试中的“关联子串”题目是一个考察字符串处理和算法理解的经典问题。以下是对该题目的详细解析&#xff1a; 一、题目描述 给定两个字符串str1 和 str2&#xff0c;如果字符串 str1 中的字符&#xff0c; 经过排列组合后的字符串中只要有一个是 str2 的子串&#xff…...

【OpenAI】第二节(Token)什么是Token?如何计算ChatGPT的Token?

深入解析&#xff1a;GPT如何计算Token数&#xff1f;让你轻松掌握自然语言处理的核心概念&#xff01;&#x1f680; 在当今的人工智能领域&#xff0c;GPT&#xff08;Generative Pre-trained Transformer&#xff09;无疑是最受关注的技术之一。无论是在文本生成、对话系统…...

GraphRAG + Ollama + Groq 构建知识库 续篇 利用neo4j显示知识库

GraphRAG Ollama Groq 构建知识库 在上一篇文章中&#xff0c;我们详细介绍了如何创建一个知识库。尽管知识库已经建立&#xff0c;但其内容的可视化展示尚未实现。我们无法直接看到知识库中的数据&#xff0c;也就无法判断这些数据是否符合我们的预期。为了解决这个问题&…...

工业以太网之战:EtherCAT是如何杀出重围的?

前言 EtherCAT 是一种开放的实时工业以太网协议&#xff0c;由德国倍福公司开发并在 2003 年 4 月的汉诺威工业博览会上首次亮相&#xff0c;目前由 EtherCAT 技术协会&#xff08;ETG&#xff09;进行维护和推广。经过 21 年的不断发展&#xff0c;EtherCAT 显示出极强的生命…...

轻量级可视化数据分析报表,分组汇总表!

什么是可视化分组汇总表&#xff1f; 可视化分组汇总表&#xff0c;是一种结合了数据分组、聚合计算与视觉呈现功能的数据分析展示功能。它能够按照指定的维度&#xff08;如时间、地区、产品类型等&#xff09;对数据进行分组&#xff0c;还能自动计算各组的统计指标&#xf…...

初始Python篇(4)—— 元组、字典

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 元组 相关概念 元组的创建与删除 元组的遍历 元组生成式 字典 相关概念 字典的创建与删除 字典的遍历与访问 字典…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...