移动端 [Android iOS] 压缩 ECDSA PublicKey
移动端 [Android & iOS] 压缩 ECDSA PublicKey
- Android
- iOS
使用 Android KeyStore 和 iOS 的 Secure Enclave 提供的安全能力使用 P-256 来对 API 请求进行签名,服务器端再进行验证。
但是发现不论是 iOS 还是安卓都没有提供一个便捷的方式从 iOS 的SecKeyCopyExternalRepresentation(SecKeyCopyPublicKey) 和 Android 的 KeyPair 中得到 33-bytes 的 compressed public key。
压缩公钥(Compressed Public Key)是一种公钥编码方式,可以将 ECC(椭圆曲线密码学)公钥从 64 个字节压缩为 33 个字节。这种编码方式由一个字节的标识符和32个字节的公钥坐标的一部分(y坐标)组成,从而实现了公钥的压缩。在使用压缩公钥时,可以减少传输的数据量和存储空间,同时保持相同的安全性和加密效果。压缩公钥广泛应用于比特币、以太坊等区块链领域中。
compressed_public_key = y is even?0x02:0x03 + x
Android
private fun secp256r1JKeyPair(packageManager: PackageManager,alias: String,throwIfNotExists: Boolean = false,
): KeyPair {val ks: KeyStore = KeyStore.getInstance(storeProvider).apply { load(null) }val keyPair: KeyPair = if (ks.containsAlias(alias)) {val entry = ks.getEntry(alias, null)if (entry !is KeyStore.PrivateKeyEntry) {throw TypeCastException()}KeyPair(entry.certificate.publicKey, entry.privateKey)} else if (throwIfNotExists) {throw KeyStoreException("No key was found with the alias $alias.")} else {val kpg: KeyPairGenerator =KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, storeProvider)var properties =KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFYval parameterSpec = KeyGenParameterSpec.Builder(alias, properties).apply {setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))setDigests(KeyProperties.DIGEST_SHA256)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && hasStrongBox(packageManager)) {setIsStrongBoxBacked(true)}}.build()kpg.initialize(parameterSpec)kpg.generateKeyPair()}return keyPair
}@OptIn(ExperimentalUnsignedTypes::class)
fun bnUByteArrayToUByteArray(bnUByteArray: UByteArray, expectLength: Int): UByteArray {if (bnUByteArray.size == expectLength + 1) {return bnUByteArray.sliceArray(1..expectLength)}if (bnUByteArray.size < expectLength) {return UByteArray(expectLength - bnUByteArray.size) { UByte.MIN_VALUE } + bnUByteArray}return bnUByteArray
}@OptIn(ExperimentalUnsignedTypes::class)
fun secp256r1PublicKey(packageManager: PackageManager,alias: String
): UByteArray {val kp = secp256r1JKeyPair(packageManager, alias)val publicKey = kp.public as ECPublicKey;val point = publicKey.wval x: BigInteger = point.affineXval y: BigInteger = point.affineYval xBytes: UByteArray = bnUByteArrayToUByteArray(x.toByteArray().toUByteArray(), 32)val yFLag = UByteArray(1)yFLag[0] = (if (y.testBit(0)) 0x03 else 0x02).toUByte()return yFLag + xBytes
}@OptIn(ExperimentalUnsignedTypes::class)
fun secp256r1Sign(packageManager: PackageManager,alias: String,payload: ByteArray
): UByteArray {val privateKey =secp256r1JKeyPair(packageManager, alias).privateval signature = Signature.getInstance(signatureAlgorithm).run {initSign(privateKey)update(payload)sign()}val seq = DERSequence.fromByteArray(signature) as DLSequenceval r = bnUByteArrayToUByteArray((seq.getObjectAt(0) as ASN1Integer).value.toByteArray().toUByteArray(), 32)val s = bnUByteArrayToUByteArray((seq.getObjectAt(1) as ASN1Integer).value.toByteArray().toUByteArray(), 32)return r + s
}@OptIn(ExperimentalUnsignedTypes::class)
private fun byteArrayToHexString(byteArray: UByteArray): String {return byteArray.joinToString(separator = "") { it.toString(16).padStart(2, '0') }
}
iOS
static func secp256r1Key(name: String, requiresBiometry: Bool = false) throws -> SecKey {let flags: SecAccessControlCreateFlags = requiresBiometry ? [.privateKeyUsage, .userPresence] : .privateKeyUsagelet access =SecAccessControlCreateWithFlags(kCFAllocatorDefault,kSecAttrAccessibleWhenUnlockedThisDeviceOnly,flags,nil)!let tag = name.data(using: .utf8)!let attributes: [String: Any] = [kSecAttrKeyType as String : kSecAttrKeyTypeEC,kSecAttrKeySizeInBits as String : 256,kSecAttrTokenID as String : kSecAttrTokenIDSecureEnclave,kSecPrivateKeyAttrs as String : [kSecAttrIsPermanent as String : true,kSecAttrApplicationTag as String : tag,kSecAttrAccessControl as String : access] as [String : Any]]var error: Unmanaged<CFError>?guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {throw error!.takeRetainedValue()}return privateKey
}static func getCompressedPublicKey(key: SecKey) throws -> Data {guard let publicKeyData = SecKeyCopyExternalRepresentation(SecKeyCopyPublicKey(key)!, nil) as? Data else {throw NSError()}let x = publicKeyData.dropFirst().prefix(32)let y = publicKeyData.subdata(in: Range(33...64))return Data([0x02 | (y.last! & 0x01)]) + x
}static func secp256r1Sign(name: String, payload: Data) -> Data {let key = secp256r1Key(name: name)var error: Unmanaged<CFError>?let asn1signature = SecKeyCreateSignature(key!, .ecdsaSignatureMessageX962SHA256, payload as CFData, &error)! as Datalet signature = try! ECSignature(asn1: asn1signature)return signature.r + signature.s
}
相关文章:
移动端 [Android iOS] 压缩 ECDSA PublicKey
移动端 [Android & iOS] 压缩 ECDSA PublicKey AndroidiOS 使用 Android KeyStore 和 iOS 的 Secure Enclave 提供的安全能力使用 P-256 来对 API 请求进行签名,服务器端再进行验证。 但是发现不论是 iOS 还是安卓都没有提供一个便捷的方式从 iOS 的SecKeyCopyE…...
Spring的配置Bean的方式
在Spring框架中,配置Bean有三种主要方式:自动装配、基于Java的显式配置和基于XML的显式配置。 1、自动装配: 自动装配是Spring容器根据Bean之间的依赖关系,自动将需要的Bean注入到目标Bean中。这是一种非常简便和快捷的配置方式&…...

安防监控/视频汇聚平台EasyCVR云端录像不展示是什么原因?该如何解决?
视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…...

毛玻璃态登录表单
效果展示 页面结构组成 通过上述的效果展示可以看出如下几个效果 底部背景有三个色块并且效果是毛玻璃效果登录表单是毛玻璃效果登录表单的周围的小方块也是有毛玻璃效果并且与登录表单有层次效果 CSS3 知识点 filter 属性backdrop-filter 属性绝对定位属性动画属性 底部背…...
Java:使用 Graphics2D 类来绘制图像
目录 过程介绍创建一个 BufferedImage 对象创建一个 Graphics2D 对象绘制字符和干扰线将生成的图像保存到文件 示例代码 过程介绍 创建一个 BufferedImage 对象 首先创建一个 BufferedImage 对象来表示图像 创建一个 Graphics2D 对象 然后使用 createGraphics() 方法创建一…...

VUE2项目:尚品汇VUE-CLI脚手架初始化项目以及路由组件分析(一)
标题 环境VUE2目录publicassetscomponentsmain.jsbabel.config.jspackage.jsonvue.config.js 项目路由分析Header与Footer非路由组件完成Header示例 路由组件的搭建声明式导航编程式导航 Footer组件的显示与隐藏路由传递参数重写push和replace三级联动组件拆分附件 环境 前提要…...
输入网址input,提取标题和正文
https://m.51cmm.com/wz/WZnKubw1.html?share_token715beaff-33ef-466b-8b6c-092880b9a716&tt_fromcopy_link&utm_sourcecopy_link&utm_mediumtoutiao_android&utm_campaignclient_share - 【科学决策七步骤 - 希律心理】 - 今日头条 提取标题和正文input输…...
docker--redis容器部署及与SpringBoot整合
1. 容器化部署docker 拉取镜像创建数据目录data 及 配置目录conf创建配置文件redis.conf启动redis容器进入容器,进行Redis操作设置为自启动:docker update redis --restart=alwaysdocker pull redis:5.0.12docker run -d --rm --name my_redis -p 6379:6379 -v D:/docker/red…...
数据库:Hive转Presto(二)
继续上节代码,补充了replace_func函数, import re import os from tkinter import *class Hive2Presto:def __int__(self):self.t_funcs [substr, nvl, substring, unix_timestamp] \[to_date, concat, sum, avg, abs, year, month, ceiling, floor]s…...

docker安装apisix全教程包含windows和linux
docker安装apisix 一、Windows安装1、首先需要安装docker和docker compose,如果直接安装docker desktop,会自动安装docker compose。2、重新启动电脑3、访问 Docker 的下载([https://www.docker.com/products/docker-desktop](https://www.do…...

【C++进阶】:C++11
C11 一.统一列表的初始化1.{}初始化2.initializer_list 二.声明1.decltype2.nullptr 三.右值引用和移动语义1.左值和右值1.转义语句2.完美转发 四.可变参数模板1.基本概念2.STL里emplace类接口 五.lambda表达式六.新的类功能 一.统一列表的初始化 1.{}初始化 在C98中…...

9.30消息队列实现进程之间通信方式代码,现象
服务端 #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)typedef struct{ long msgtype; //消息类型char data[1024]; //消息正文 }Msg;#define SIZE sizeof(Msg)-sizeof(long)int main(int argc…...
【Oracle】Oracle系列之十三--游标
文章目录 往期回顾前言1. 游标的定义2. 游标的类型(1)显式游标(2)隐式游标 3. 游标的应用(1)基本用法(2)数据处理(3)更新数据(4)注意事…...

【Linux】——基操指令(二)
个人主页 代码仓库 C语言专栏 初阶数据结构专栏 Linux专栏 LeetCode刷题 算法专栏 目录 前言 man指令 cp 指令 mv指令 echo指令 cat指令 more指令 less指令 head和tail指令 head指令 tail指令 前言 上篇文章给大家讲解了Linux环境下的一点基操指令…...
如何用Angular和NativeScript开发IOS程序?
要使用Angular和NativeScript开发iOS应用程序,您可以按照以下步骤进行操作: 安装必要的工具: 确保您已经安装了Node.js和npm(Node.js包管理器)。 安装Angular CLI:如果尚未安装,请运行以下命令…...
python 使用 scapy 扫描内网IP或端口
地址信息在IP层, 可以利用 ICMP 或 ARP 协议数据包探测IP信息. ICMP协议可以利用ping工具发送数据包, 但是防火墙有可能禁止ICMP, 无法有效探测, 可以考虑使用ARP探测. 利用ICMP协议探测内网IP def ping_ip(ip_fex):# 扫描范围: 128~254for i in range(128, 255):ip f{ip_fe…...

14:00面试,14:08就出来了,问的问题有点变态
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%,…...

Spring Security 简单token配置
Spring Security 简单token配置 说明:非表单配置 先上码: https://gitee.com/qkzztx_admin/security-demo/tree/master/demo-two 环境:win10 idea2023 springboot2.7.6 maven3.8.6 代码清单说明 依赖: <dependency><…...

2023 “华为杯” 中国研究生数学建模竞赛(F题)深度剖析|数学建模完整代码+建模过程全解全析
F题代码思路 当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2021年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。 让我们一起看看研赛的F题呀!全文都已…...

FFmpeg 命令:从入门到精通 | ffplay 简单过滤器
FFmpeg 命令:从入门到精通 | ffplay 简单过滤器 FFmpeg 命令:从入门到精通 | ffplay 简单过滤器视频旋转视频反转视频旋转和反转音频变速播放视频变速播放音视频同时变速更多参考 FFmpeg 命令:从入门到精通 | ffplay 简单过滤器 本节介绍了简…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...