iOS BLE蓝牙开发数据传输协议详解 常用算法(AES加密 HMAC_hash PRF)

article/2025/8/16 1:08:34

前言

这段时间参与了一款与蓝牙外设交互的项目, 以前没有涉及过数据传输方面的开发, 踩了不少坑, 同时也学到了很多东西. 此时, 项目也即将进入尾声, 有时间把这些记录一二. 本人才疏学浅, 如有错误,大佬轻喷.

BLE4.0开发

这方面网上的Demo一大堆, 暂时不做太多的赘述, 只对坑点做一个摘要.

  1. 需求使然, 要对设备的接近远离有一个比较精确的计算, 使用的方案是对蓝牙的信号强度进行分析. 然而, 信号强度的波动值较大, 很难得出较为精确的值, 于是乎需要较多的信号值进行计算, iOS可以通过[self.peripheral readRSSI]来读取信号值强度, 但是该方法最快1s只能返回一次, 如果需要更快速的获取信号值强度, 执行scanForPeripheralsWithServices方法设置options参数@{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)}, 也许iBeacon会是个不错的选择, 但是这边硬件并不支持,也没有进行实际的测试.
  2. 获取蓝牙外设mac地址的问题, 众所周知的隐私问题, 目前iOS并不能获取到. 解决方法是让硬件工程师把mac地址写入到广播包中的kCBAdvDataManufacturerData这个key中,在发现外设的回调centralManager: didDiscoverPeripheral: advertisementData: RSSI:中的advertisementData参数中获取. (一定要写在对应kCBAdvDataManufacturerData的字段中, 发现该设备广播包中没有这个key, 让硬件工程师换一个字段再试试, 各个厂家的蓝牙模块不一样, 很可能硬件工程师写错了)

数据传输

首先是平台方面的人定好了数据传输协议, 我们按协议进行拼接, 然后使用拼接好的数据与外设进行交互.
数据传输协议一般分为包头和包体, 包体中也许还会进行类似的嵌套. 协议中会定义传输 的数据类型, 比如拼接过程中需要传入包体的长度(无符号双字节整型), 我们一般会用int取到长度length, 这时候需要把int转化为两个Byte.

// int转两个字节Byte
+ (NSData *)dataFromShort:(short)value {Byte bytes[2] = {};for (int i = 0; i < 2; i++) {int offset = 16 - (i + 1) * 8;bytes[i] = (Byte) ((value >> offset) & 0xff);}NSData *data = [[NSData alloc] initWithBytes:bytes length:2];return data;
}// int转四个字节Byte
+ (NSData *)dataFromInt:(int)value {Byte bytes[4] = {};for (int i = 0; i < 4; i++) {bytes[i] = (Byte)(value >> (24 - i * 8));}NSData *data= [[NSData alloc] initWithBytes:bytes length:4];return data;
}

更多:

一般也会有时间戳, 需要拼接这里提供两种格式的时间戳.

// 6个字节的时间戳
+ (NSData *)currentTimeData {Byte bytes[6];NSCalendar *calendar = [NSCalendar currentCalendar];NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:[NSDate date]];int year =(int) [dateComponent year];int month = (int) [dateComponent month];int day = (int) [dateComponent day];int hour = (int) [dateComponent hour];int minute = (int) [dateComponent minute];int second = (int) [dateComponent second];bytes[0] = year - 2000;bytes[1] = month;bytes[2] = day;bytes[3] = hour;bytes[4] = minute;bytes[5] = second;return [[NSData alloc] initWithBytes:bytes length:6];
}// 4个字节的时间戳
+ (NSData *)timestampData {int time = [[NSDate date] timeIntervalSince1970];return [NSData dataFromInt:time];
}

常用算法

PRF算法

首先来看一下PRF算法,这个之前一直想在网上download一份, 奈何实在没有找到. 猜测是前端一般不会用到, 安卓同事倒是从平台处得到了封装好的jar包可以使用. iOS这边只能自己动手实现, 下面先看一下PRF算法的实现原理:

PRF算法

实现如下:

+ (NSData *)tf_prfSecret:(NSData *)secret label:(NSData *)label seed:(NSData *)seed {// 讲label与seed进行拼接NSMutableData *seedData = [NSMutableData data];[seedData appendData:label];[seedData appendData:seed];return [self tf_prfSecret:secret seed:seedData];
}+ (NSData *)tf_prfSecret:(NSData *)secret seed:(NSData *)seed {NSMutableData *prfData = [NSMutableData data];NSMutableData *mutableData = [NSMutableData dataWithData:seed];NSData *AnData = [NSData dataWithData:seed];// 需要prf算法得出的长度// kStaticPrfMinimumLength: 根据需求需要写入while (prfData.length < kStaticPrfMinimumLength) {AnData = [self hmacSHA256WithSecret:secret content:AnData];mutableData = [NSMutableData dataWithData:AnData];[mutableData appendData:seed];NSData *hmacData = [self hmacSHA256WithSecret:secret content:mutableData];[prfData appendData:hmacData];}return prfData;
}

HMAC_SHA256算法

PRF算法中, HMAC_hash算法是可选的, 这边使用的是SHA256, 实现如下:

// hmac sha256算法
+ (NSData *)hmacSHA256WithSecret:(NSData *)secret content:(NSData *)content {unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];CCHmac(kCCHmacAlgSHA256, secret.bytes, secret.length, content.bytes, content.length, cHMAC);NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];//    将data按string输出//    const unsigned char *buffer = (const unsigned char *)[HMACData bytes];//    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];//    for (int i = 0; i < HMACData.length; ++i){//        [HMAC appendFormat:@"%02x", buffer[i]];return HMACData;
}

AES128加密

网上这样的加密真是一大堆,这边因为是与硬件数据传输, 所以对数据进行的加密的密钥与iv向量也大概率是直接便是Data而不是常用的NSString, 这边对两种类型的keyiv都做了实现, 按实际情景使用.

- (NSData *)tf_encryptAES128WithKey:(NSString *)key iv:(NSString *)iv {return [self tf_AES128Operation:kCCEncrypt key:key iv:iv];
}- (NSData *)tf_decryptAES128WithKey:(NSString *)key iv:(NSString *)iv {return [self tf_AES128Operation:kCCDecrypt key:key iv:iv];
}- (NSData *)tf_encryptAES128WithKeyData:(NSData *)keyData ivData:(NSData *)ivData {return [self tf_AES128Operation:kCCEncrypt keyData:keyData ivData:ivData];
}- (NSData *)tf_decryptAES128WithKeyData:(NSData *)keyData ivData:(NSData *)ivData {return [self tf_AES128Operation:kCCDecrypt keyData:keyData ivData:ivData];
}/****  @param operation kCCEncrypt:加密  kCCDecrypt:解密*  @param key       公钥*  @param iv        偏移量**  @return 加密或者解密的NSData*/- (NSData *)tf_AES128Operation:(CCOperation)operation key:(NSString *)key iv:(NSString *)iv {char keyBytes[kCCKeySizeAES128 + 1];  //kCCKeySizeAES128是加密位数 可以替换成256位的// bzero函数:从字符串第一位开始置0, 第二个参数代表置0的位数// 相当于memset(keyBytes,0x00,sizeof(keyBytes));bzero(keyBytes, sizeof(keyBytes));[key getCString:keyBytes maxLength:sizeof(keyBytes) encoding:NSUTF8StringEncoding];// ivchar ivBytes[kCCBlockSizeAES128 + 1];bzero(ivBytes, sizeof(ivBytes));[iv getCString:ivBytes maxLength:sizeof(ivBytes) encoding:NSUTF8StringEncoding];return [self tf_cryptAES128Operation:operation keyBytes:keyBytes ivBytes:ivBytes];
}- (NSData *)tf_AES128Operation:(CCOperation)operation keyData:(NSData *)keyData ivData:(NSData *)ivData {char keyBytes[kCCKeySizeAES128 + 1];bzero(keyBytes, sizeof(keyBytes));[keyData getBytes:keyBytes length:sizeof(keyBytes)];char ivBytes[kCCKeySizeAES128 + 1];bzero(ivBytes, sizeof(ivBytes));[ivData getBytes:ivBytes length:sizeof(ivBytes)];return [self tf_cryptAES128Operation:operation keyBytes:keyBytes ivBytes:ivBytes];
}- (NSData *)tf_cryptAES128Operation:(CCOperation)operation keyBytes:(void *)keyBytes ivBytes:(void *)ivBytes {size_t bufferSize = self.length + kCCBlockSizeAES128;void *buffer = malloc(bufferSize);size_t numBytesCrypted = 0;/*CCOptions 默认为CBC加密选择ECB加密填: kCCOptionPKCS7Padding | kCCOptionECBModeECB模式iv向量填NULLkCCOptionPKCS7Padding: 7填充直接填0x0000: 就是No padding填充*/CCCryptorStatus cryptorStatus = CCCrypt(operation, kCCAlgorithmAES128,kCCOptionPKCS7Padding,keyBytes,kCCKeySizeAES128,ivBytes,self.bytes,self.length,buffer,bufferSize,&numBytesCrypted);if(cryptorStatus == kCCSuccess) {NSLog(@"Crypt Successfully");NSData *result = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];/* 转16进制字符串Byte *resultBytes = (Byte *)result.bytes;NSMutableString *outPut = [[NSMutableString alloc] initWithCapacity:result.length * 2];for (int i = 0; i < result.length; i++) {[outPut appendFormat:@"%02x", resultBytes[i]];}*/return result;} else {NSLog(@"Crypt Error");free(buffer);return nil;}
}

附上 源码Demo


http://chatgpt.dhexx.cn/article/3jCrneqw.shtml

相关文章

qmake language qt 工程文件 配置文件 .pro .prl .prf .pri 词法 语法 for循环 判断语句 函数定义

目录 词法 string 1、数据类型 2、特殊处理的内置变量 3、转义字符 关键字&#xff1a;包括语法关键字、特殊变量 语法 变量 变量、属性、环境变量 变量使用 全局变量作用域 函数定义和使用 判断语句和循环语句 判断语句 判断语句 条件分支 if 案例 循环语句…

prf###.tmp临时文件导致磁盘资源不足

[问题现象] 客户反馈数据库服务器C盘空间严重不足&#xff0c;只有2GB可用空间。 [问题分析] 通过工程师分析检查&#xff0c;空间占用最多的文件是临时文件而且无法直接删除。临时文件格式是prf###.tmp ※ 此文件格式曾经遇到过&#xff0c;我有一些印象的。不过为指导工程师…

基于RTT压缩包C基础-不明白的接口PRF_ENV_GET __attribute__

回答----https://blog.csdn.net/weixin_42381351/article/details/115524780?spm1001.2014.3001.5501 用户APP里面 函数 struct custs1_env_tag *custs1_env PRF_ENV_GET(CUSTS1, custs1); 这个是一个指针 分配内存 但是右边是强转的 实际上右边结构体要小呀 安不安全&…

Qt之pro、pri、prf、prl文件简解

pro文件 QT工程的pro文件&#xff0c;在创建工程时由QTCreater自动创建&#xff0c;我们可以往里面添加内容&#xff0c;增加库文件的声明&#xff0c;包含路径、预处理器定义&#xff0c;生成目录&#xff0c;输出中间目录等等设置。 注释: 以“#”开始&#xff0c;到这一行结…

matlab sar 斑马图,星载滑动聚束SAR卫星姿态和PRF序列设计方法与流程

本发明涉及星载合成孔径雷达系统参数设计技术领域&#xff0c;特别涉及星载滑动聚束SAR卫星系统参数设计&#xff0c;具体是一种星载滑动聚束SAR卫星姿态和PRF序列设计方法&#xff0c;可用于星载滑动聚束合成孔径雷达系统参数设计。 背景技术&#xff1a; 合成孔径雷达可以全天…

PRF 快排系统

简介&#xff1a; PRF快排系统包含WEB管理后台、刷词软件&#xff0c;二者一对N配合使用。刷词软件部分基于模拟点击原理&#xff0c;具有稳定性&#xff0c;避免因刷词带来的K站风险。 WEB管理后台&#xff1a;基于JAVA语言开发&#xff0c;MySql数据库&#xff0c;支持Window…

Efficient Batched Oblivious PRF -Private Set Intersection

论文分享&#xff01;《Efficient Batched Oblivious PRF with Applications to Private Set Intersection》--《高效批处理不经意伪随机数生成器及其在隐私集合求交中的应用》 今天介绍一篇CCS2016顶会上的文章&#xff0c;该会专注于信息安全领域实用性的论文。本文介绍的这篇…

密码学之PRP/PRF转换引理

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 本文将介绍密码学中的PRF、PRP等相关概念&#xff0c;并介绍 PRP/PRF 转换引理及其证明&#xff0c;希望读完本文后&#xf…

雷达基础知识:脉冲重复频率(PRF)

大家都知道&#xff0c;对于脉冲体制的雷达信号&#xff0c;它有一个重要的参数是脉冲重复频率(PRF)。那么&#xff0c;雷达的重频一般会有哪些变化呢&#xff1f; 重频固定 对 于常规雷达&#xff0c;PRF通常是不变的&#xff0c;也就是说脉冲重复间隔(PRI)是固定的。 示意图…

nifi入门(2)-nifi的简单使用示例

NiFi术语 为了谈论NiFi&#xff0c;用户或者是开发都应该熟悉一些nifi相关的关键术语&#xff0c;一些术语将会贯穿全文。 我们将在此重点介绍两个最重要的术语: FlowFile: 每条“用户数据”&#xff08;即&#xff0c;用户通过NiFi获取或者是生成的&#xff0c;需要进行处理和…

Apache NiFi简介

一个易用、强大、可靠的数据处理与分发系统。基于Web图形界面&#xff0c;通过拖拽、连接、配置完成基于流程的编程&#xff0c;实现数据采集等功能 一、什么是NiFi? NiFi是美国国家安全局开发并使用了8年的可视化数据集成产品&#xff0c;2014年NAS将其贡献给了Apache社区&am…

【NiFi】(一)NiFi 简介及核心概念

文章目录 一、简介二、NiFi 核心概念三、设计模型四、NiFi 架构五、NiFi 的性能期望与特点六、NiFi 功能的高级概述 一、简介 Apache NiFi 是一个易于使用、功能强大而且可靠的数据拉取、数据处理和分发系统&#xff0c;用于自动化管理系统间的数据流。它支持高度可配置的指示…

nifi从入门到实战(保姆级教程)——环境篇

背景&#xff1a; 公司领导决定将各种基础数据的导入从代码中分离出来&#xff0c;用Apache Nifi替换。使开发者们更关注在业务上&#xff0c;而不用关心基础的由来。 Apache Nifi对于整个团队都是一个全新的工具&#xff0c;之前大家都没有接触过&#xff0c;甚至是第一次听说…

1、nifi-1.9.2介绍、单机部署及简单验证

Apache NiFi系列文章 1、nifi-1.9.2介绍、单机部署及简单验证 2、NIFI应用示例-GetFile和PutFile应用 3、NIFI处理器介绍、FlowFlie常见属性、模板介绍和运行情况信息查看 4、集群部署及验证、监控及节点管理 5、NiFi FileFlow示例和NIFI模板示例 6、NIFI应用场景-离线同步Mys…

Nifi集群安装配置

机器 目录 免密登录 nifi001d /opt/software/nifi nifi001d>>nifi002d、nifi003d niif002d /opt/software/nifi nifi002d>>nifi001d、nifi003d niif002d /opt/software/nifi nifi003d>>nifi001d、nifi002d 1、安装nifi &#xff08;1&#xff…

NIFI 入门使用

1. Kettle与NIFI差异 Kettle 介绍 Kettle是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c;绿色无需安装&#xff0c;数据抽取高效稳定。Kettle 中文名称叫水壶&#xff0c;该项目的主程序员MATT 希望把各种数据放到一…

《数据同步-NIFI系列》Nifi详细教程入门-06Nifi基础操作

Nifi基础操作 1 主页面 2 组 2.1 创建组 从常用功能模块&#xff0c;拖动组到画布上&#xff0c;自定义组名。可以通过鼠标移动组在画布位置。 2.2 进入、退出组 选中某一个组&#xff0c;单击右键选择enter group或者双击组进入组内&#xff0c;在组内单击右键选择leave g…

nifi-搭建

NIFI 简介 1、NIFI 的概念 1.1 起源&#xff1a;NIFI是为了自动化的处理和管理系统之间的数据流而产生的&#xff0c;基本设计概念与基于流的编程[fbp]的主要思想密切相关 1.2 nifi核心概念 FlowFile&#xff1a;FlowFile表示通过系统移动的每个对象&#xff0c;包含数据流的基…

9、NIFI综合应用场景-通过NIFI配置kafka的数据同步

Apache NiFi系列文章 1、nifi-1.9.2介绍、单机部署及简单验证 2、NIFI应用示例-GetFile和PutFile应用 3、NIFI处理器介绍、FlowFlie常见属性、模板介绍和运行情况信息查看 4、集群部署及验证、监控及节点管理 5、NiFi FileFlow示例和NIFI模板示例 6、NIFI应用场景-离线同步Mys…

Apache NiFi 入门指南

本指南使用于谁&#xff1f; 本指南适用于从未使用过&#xff0c;在NiFi中有限度接触或仅完成特定任务的用户。本指南不是详尽的说明手册或参考指南。“ 用户指南”提供了大量信息&#xff0c;旨在提供更加详尽的资源&#xff0c;并且作为参考指南非常有用。相比之下&#xff…