在 Ubuntu 24.04.1 LTS (WSL) 中使用 openssl 生成 keybox.xml

看到“生成 keybox.xml”,大概率都会联想到 PIF 和 Tricky Store。这里就不多解释它们的用途了。最近在网上看到生成非 AOSP keybox 的教程,在这里做一些补充,并将代码打包成一个 Python 脚本。

参考自:

  1. Idea 提供者:https://xdaforums.com/t/tee-hacking.4662185/page-21#post-89847987(如果打不开或者被重定向去另一个网页可能要刷新几遍才能正确打开这个网页) ,该原始 Idea 需要借助一个密码学工具网站;
  2. RSA 私钥转换:https://stackoverflow.com/questions/17733536/how-to-convert-a-private-key-to-an-rsa-private-key。

做出以下调整:

  1. 直接使用一站式脚本执行,自动利用 openssl 生成三个 PEM 文件,如果用于预检测的 openssl version 命令执行失败,自动尝试通过 sudo apt-get install libssl-dev 进行安装;
  2. 实现对新版 openssl 生成的 RSA 私钥进行识别,并从 PKCS8 转换为 PKCS1。

直接上 Python 代码,记得以 LF 形式保存换行符,并在 Ubuntu 24.04.1 LTS 中运行。

import os
try:os.chdir(os.path.abspath(os.path.dirname(__file__)))
except:pass
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
EOF = (-1)
keyboxFormatter = """<?xml version="1.0"?>
<AndroidAttestation>
<NumberOfKeyboxes>1</NumberOfKeyboxes>
<Keybox DeviceID="YourDeviceID">
<Key algorithm="ecdsa">
<PrivateKey format="pem">
{0}</PrivateKey>
<CertificateChain>
<NumberOfCertificates>1</NumberOfCertificates>
<Certificate format="pem">
{1}</Certificate>
</CertificateChain>
</Key>
<Key algorithm="rsa">
<PrivateKey format="pem">
{2}</PrivateKey>
</Key>
</Keybox>
</AndroidAttestation>"""def execute(commandline:str) -> int|None:if isinstance(commandline, str):print("$ " + commandline)return os.system(commandline)else:return Nonedef handleOpenSSL(flag:bool = True) -> bool|None:if isinstance(flag, bool):errorLevel = execute("openssl version")if EXIT_SUCCESS == errorLevel:return Trueelif flag: # can try againexecute("sudo apt-get install openssl libssl-dev")return handleOpenSSL(False)else:return Falseelse:return Nonedef pressTheEnterKeyToExit(errorLevel:int|None = None):try:print("Please press the enter key to exit ({0}). ".format(errorLevel) if isinstance(errorLevel, int) else "Please press the enter key to exit. ")input()except:passdef main() -> int:# Parameters #failureCount = 0ecPrivateKeyFilePath = "ecPrivateKey.pem"certificateFilePath = "certificate.pem"rsaPrivateKeyFilePath = "rsaPrivateKey.pem"oldRsaPrivateKeyFilePath = "oldRsaPrivateKey.pem"keyboxFilePath = "keybox.xml"# First-phase Generation #failureCount += execute("openssl ecparam -name prime256v1 -genkey -noout -out \"{0}\"".format(ecPrivateKeyFilePath)) != 0failureCount += execute("openssl req -new -x509 -key \"{0}\" -out {1} -days 3650 -subj \"/CN=Keybox\"".format(ecPrivateKeyFilePath, certificateFilePath)) != 0failureCount += execute("openssl genrsa -out \"{0}\" 2048".format(rsaPrivateKeyFilePath)) != 0if failureCount > 0:print("Cannot generate a sample ``keybox.xml`` file since {0} PEM file{1} not generated successfully. ".format(failureCount, ("s were" if failureCount > 1 else " was")))pressTheEnterKeyToExit(EOF)return EOF# First-phase Reading #try:with open(ecPrivateKeyFilePath, "r", encoding = "utf-8") as f:ecPrivateKey = f.read()with open(certificateFilePath, "r", encoding = "utf-8") as f:certificate = f.read()with open(rsaPrivateKeyFilePath, "r", encoding = "utf-8") as f:rsaPrivateKey = f.read()except BaseException as e:print("Failed to read one or more of the PEM files. Details are as follows. \n{0}".format(e))pressTheEnterKeyToExit(EOF)return EOF# Second-phase Generation #if rsaPrivateKey.startswith("-----BEGIN PRIVATE KEY-----"):print("A newer openssl version is used. The RSA private key in the PKCS8 format will be converted to that in the PKCS1 format soon. ")failureCount += execute("openssl rsa -in \"{0}\" -out \"{1}\" -traditional".format(rsaPrivateKeyFilePath, oldRsaPrivateKeyFilePath))if failureCount > 0:print("Cannot convert the RSA private key in the PKCS8 format to that in the PKCS1 format. ")pressTheEnterKeyToExit(EOF)return EOFelse:print("Finished converting the RSA private key in the PKCS8 format to that in the PKCS1 format. ")try:with open(oldRsaPrivateKeyFilePath, "r", encoding = "utf-8") as f:rsaPrivateKey = f.read()except BaseException as e:print("Failed to update the RSA private key from \"{0}\". Details are as follows. \n{1}".format(oldRsaPrivateKeyFilePath, e))pressTheEnterKeyToExit(EOF)return EOF# Keybox Generation #keybox = keyboxFormatter.format(ecPrivateKey, certificate, rsaPrivateKey)print(keybox)try:with open(keyboxFilePath, "w", encoding = "utf-8") as f:f.write(keybox)print("Successfully wrote the keybox to \"{0}\". ".format(keyboxFilePath))pressTheEnterKeyToExit(EXIT_SUCCESS)return EXIT_SUCCESSexcept BaseException as e:print("Failed to write the keybox to \"{0}\". Details are as follows. \n{1}".format(keyboxFilePath, e))pressTheEnterKeyToExit(EXIT_FAILURE)return EXIT_FAILUREif "__main__" == __name__:exit(main())

替换 /data/adb/tricky_store/keybox.xml 之前,记得先将原来的 keybox.xml(刷入 tricky_store 时自带的那个基于 AOSP 的 keybox.xml)备份为 keybox.xml.bak
截图
12月14日凌晨做了一些更新:

  1. 支持粗略检查三个子密钥文件内容,支持 OpenSSL 私钥转 RSA 私钥;
  2. 如果文件存在,程序会提示是否覆盖;
  3. 设备ID随机生成。
import os
from random import randint, choice
from base64 import b64decode
try:os.chdir(os.path.abspath(os.path.dirname(__file__)))
except:pass
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
EOF = (-1)
LB = 2 # the lower bound of the length of the device ID
UB = 12 # the upper bound of the length of the device ID
CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
keyboxFormatter = """<?xml version="1.0"?>
<AndroidAttestation>
<NumberOfKeyboxes>1</NumberOfKeyboxes>
<Keybox DeviceID="{0}">
<Key algorithm="ecdsa">
<PrivateKey format="pem">
{1}</PrivateKey>
<CertificateChain>
<NumberOfCertificates>1</NumberOfCertificates>
<Certificate format="pem">
{2}</Certificate>
</CertificateChain>
</Key>
<Key algorithm="rsa">
<PrivateKey format="pem">
{3}</PrivateKey>
</Key>
</Keybox>
</AndroidAttestation>
"""def canOverwrite(flags:list, idx:int, prompts:str|tuple|list|set) -> bool:if isinstance(flags, list) and isinstance(idx, int) and -len(flags) <= idx < len(flags) and isinstance(prompts, (str, tuple, list, set)):try:if isinstance(prompts, str):print("\"{0}\"".format(prompts))choice = input("The file mentioned above exists. Overwrite or not [aYn]? ")else:print(prompts)choice = input("At least one of the files mentioned above exists. Overwrite or not [aYn]? ")if choice.upper() == "A":for i in range((idx if idx >= 0 else len(flags) + idx), len(flags)): # overwirte the current file and all the following necessary files no matter whether they existflags[i] = Truereturn Trueelif choice.upper() == "N":return Falseelse:flags[idx] = Truereturn Trueexcept BaseException as e:print(e)return Falseelse:input("#")return Falsedef execute(commandline:str) -> int|None:if isinstance(commandline, str):print("$ " + commandline)return os.system(commandline)else:return Nonedef handleOpenSSL(flag:bool = True) -> bool|None:if isinstance(flag, bool):errorLevel = execute("openssl version")if EXIT_SUCCESS == errorLevel:return Trueelif flag: # can try againexecute("sudo apt-get install openssl libssl-dev")return handleOpenSSL(False)else:return Falseelse:return Nonedef pressTheEnterKeyToExit(errorLevel:int|None = None):try:print("Please press the enter key to exit ({0}). ".format(errorLevel) if isinstance(errorLevel, int) else "Please press the enter key to exit. ")input()except:passdef main() -> int:# Parameters #failureCount = 0deviceID = "".join([choice(CHARSET) for _ in range(randint(LB, UB))]) # or specify the device ID manually like "YourDeviceID"ecPrivateKeyFilePath = "ecPrivateKey.pem"certificateFilePath = "certificate.pem"rsaPrivateKeyFilePath = "rsaPrivateKey.pem"keyboxFilePath = "keybox.xml" # None for no files writtenflags = [not (os.path.isfile(ecPrivateKeyFilePath) or os.path.isfile(certificateFilePath)), not os.path.isfile(rsaPrivateKeyFilePath), not os.path.isfile(keyboxFilePath)]# First-phase Generation #if flags[0] or canOverwrite(flags, 0, (ecPrivateKeyFilePath, certificateFilePath)):failureCount += execute("openssl ecparam -name prime256v1 -genkey -noout -out \"{0}\"".format(ecPrivateKeyFilePath)) != 0if flags[0] or not os.path.isfile(certificateFilePath):failureCount += execute("openssl req -new -x509 -key \"{0}\" -out {1} -days 3650 -subj \"/CN=Keybox\"".format(ecPrivateKeyFilePath, certificateFilePath)) != 0if flags[1] or canOverwrite(flags, 1, rsaPrivateKeyFilePath):failureCount += execute("openssl genrsa -out \"{0}\" 2048".format(rsaPrivateKeyFilePath)) != 0if failureCount > 0:print("Cannot generate a sample ``keybox.xml`` file since {0} PEM file{1} not generated successfully. ".format(failureCount, ("s were" if failureCount > 1 else " was")))pressTheEnterKeyToExit(11)return 11# First-phase Reading #try:with open(ecPrivateKeyFilePath, "r", encoding = "utf-8") as f:ecPrivateKey = f.read()with open(certificateFilePath, "r", encoding = "utf-8") as f:certificate = f.read()with open(rsaPrivateKeyFilePath, "r", encoding = "utf-8") as f:rsaPrivateKey = f.read()except BaseException as e:print("Failed to read one or more of the PEM files. Details are as follows. \n{0}".format(e))pressTheEnterKeyToExit(12)return 12# Second-phase Generation #if flags[1]: # only updates the key content when the original key is newly generated or updating is allowedif rsaPrivateKey.startswith("-----BEGIN PRIVATE KEY-----") and rsaPrivateKey.rstrip().endswith("-----END PRIVATE KEY-----"):print("A newer openssl version is used. The RSA private key in the PKCS8 format will be converted to that in the PKCS1 format soon. ")failureCount += execute("openssl rsa -in \"{0}\" -out \"{0}\" -traditional".format(rsaPrivateKeyFilePath))if failureCount > 0:print("Cannot convert the RSA private key in the PKCS8 format to that in the PKCS1 format. ")pressTheEnterKeyToExit(13)return 13else:print("Finished converting the RSA private key in the PKCS8 format to that in the PKCS1 format. ")try:with open(rsaPrivateKeyFilePath, "r", encoding = "utf-8") as f:rsaPrivateKey = f.read()except BaseException as e:print("Failed to update the RSA private key from \"{0}\". Details are as follows. \n{1}".format(rsaPrivateKeyFilePath, e))pressTheEnterKeyToExit(14)return 14elif rsaPrivateKey.startswith("-----BEGIN OPENSSH PRIVATE KEY-----") and rsaPrivateKey.rstrip().endswith("-----END OPENSSH PRIVATE KEY-----"):print("An OpenSSL private key is detected, which will be converted to the RSA private key soon. ")failureCount += execute("ssh-keygen -p -m PEM -f \"{0}\" -N \"\"".format(rsaPrivateKeyFilePath))if failureCount > 0:print("Cannot convert the OpenSSL private key to the RSA private key. ")pressTheEnterKeyToExit(15)return 15else:print("Finished converting the OpenSSL private key to the RSA private key. ")try:with open(rsaPrivateKeyFilePath, "r", encoding = "utf-8") as f: # the ``ssh-keygen`` overwrites the file though no obvious output filepaths specifiedrsaPrivateKey = f.read()except BaseException as e:print("Failed to update the RSA private key from \"{0}\". Details are as follows. \n{1}".format(rsaPrivateKeyFilePath, e))pressTheEnterKeyToExit(16)return 16# Brief Checks #if not (ecPrivateKey.startswith("-----BEGIN EC PRIVATE KEY-----") and ecPrivateKey.rstrip().endswith("-----END EC PRIVATE KEY-----")):print("An invalid EC private key is detected. Please try to use the latest key generation tools to solve this issue. ")pressTheEnterKeyToExit(17)return 17if not (certificate.startswith("-----BEGIN CERTIFICATE-----") and certificate.rstrip().endswith("-----END CERTIFICATE-----")):print("An invalid certificate is detected. Please try to use the latest key generation tools to solve this issue. ")pressTheEnterKeyToExit(18)return 18if not (rsaPrivateKey.startswith("-----BEGIN RSA PRIVATE KEY-----") and rsaPrivateKey.rstrip().endswith("-----END RSA PRIVATE KEY-----")):print("An invalid final RSA private key is detected. Please try to use the latest key generation tools to solve this issue. ")pressTheEnterKeyToExit(19)return 19# Keybox Generation #keybox = keyboxFormatter.format(deviceID, ecPrivateKey, certificate, rsaPrivateKey)print("Generated keybox with a length of {0}: ".format(len(keybox)))print(keybox)if keyboxFilePath is not None and (flags[2] or canOverwrite(flags, 2, keyboxFilePath)):try:with open(keyboxFilePath, "w", encoding = "utf-8") as f:f.write(keybox)print("Successfully wrote the keybox to \"{0}\". ".format(keyboxFilePath))pressTheEnterKeyToExit(EXIT_SUCCESS)return EXIT_SUCCESSexcept BaseException as e:print("Failed to write the keybox to \"{0}\". Details are as follows. \n{1}".format(keyboxFilePath, e))pressTheEnterKeyToExit(20)return 20else:print("The keybox has not been written to any files. Please refer to the text above. ")pressTheEnterKeyToExit(EXIT_FAILURE)return EXIT_FAILUREif "__main__" == __name__:exit(main())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/64031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis篇-1--入门介绍

1、Redis概述 ‌Redis&#xff08;Remote Dictionary Server&#xff09;&#xff0c;全称为远程字典服务。‌是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。 Redis提供了多种数据类型的存储&#xff0c;来适应不同场景下的存储需…

antdv-<a-button>中属性的使用

UI组件库&#xff08;User Interface Component Library&#xff09;是一种预先构建好的、可重用的用户界面元素集合&#xff0c;旨在帮助开发者更快速、更简便地构建用户界面。这些组件通常包括按钮、表单、导航栏、模态框等&#xff0c;能够提供一致的外观和交互风格&#xf…

简单的多网卡选择指定网卡ip注册

简单的多网卡选择指定网卡ip注册 我们公司服务器上面有多个网卡&#xff0c;多网卡则本地ip有多个ip,我们启动服务的时候需要选定他特定的ip&#xff0c;我们服务需要特定的ip进行注册&#xff0c;才能进行正常的通讯功能&#xff0c;我们需要使用如下配置进行特定ip选择&…

鸿蒙NEXT开发案例:颜文字搜索器

【引言】 本文将介绍一个名为“颜文字搜索器”的开发案例&#xff0c;该应用是基于鸿蒙NEXT平台构建的&#xff0c;旨在帮助用户快速查找和使用各种风格的表情符号。通过本案例的学习&#xff0c;读者可以了解如何在鸿蒙平台上进行数据处理、UI设计以及交互逻辑的实现。 【环…

快速部署一套K8s集群-v1.28

快速部署一套K8s集群-v1.28 1.前置知识点 1.1 生产环境可部署Kubernetes集群的两种方式 目前生产部署Kubernetes集群主要有两种方式: kubeadmKubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。 二进制包从github下载发行版的二进…

【硬件测试】基于FPGA的4ASK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.Verilog核心程序 4.开发板使用说明和如何移植不同的开发板 5.完整算法代码文件获得 1.算法仿真效果 本文是之前写的文章: 《基于FPGA的4ASK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR》 的…

用友U8+ API接口使用教程

前言 U8和其他的公开的开放API接口有一些差异&#xff0c;他是需要先对接的到代理服务器&#xff0c;通过代理服务器进行对接&#xff0c;所以只要保证U8能上网就能对接&#xff0c;和畅捷通T的模式有点类似 流程&#xff1a; 注册成为开发者&#xff08;用于创建用友U8 API应…

检查读取数据寄存器输出的多扇出

为使第二寄存器被 RAM 原语吸收&#xff0c;来自存储器阵列的数据输出位的扇出必须为 1 。这在下图中进行了说明。 检查地址 / 读取数据寄存器上的复位信号 不应复位存储器阵列。只有 RAM 的输出可以容许复位。复位必须是同步的&#xff0c;以便将输出寄存器推断到 RAM 基元…

MongoDB-ObjectID 生成器

前言 MongoDB中一个非常关键的概念就是 ObjectID&#xff0c;它是 MongoDB 中每个文档的默认唯一标识符。了解 ObjectID 的生成机制不仅有助于开发人员优化数据库性能&#xff0c;还能帮助更好地理解 MongoDB 的设计理念。 什么是 MongoDB ObjectID&#xff1f; 在 MongoDB …

渗透测试工具 -- SQLmap安装教程及使用

随着网络安全问题日益严峻&#xff0c;渗透测试成为了保护信息安全的重要手段。而在渗透测试的众多工具中&#xff0c;SQLmap凭借其强大的自动化SQL注入检测和利用能力&#xff0c;成为了网络安全专家必备的利器。那么&#xff0c;你知道如何高效地使用SQLmap进行漏洞扫描吗&am…

SpringBoot 整合 RabbitMQ 实现流量消峰

RabbitMQ 即一个消息队列&#xff0c;主要是用来实现应用程序的异步和解耦&#xff0c;同时也能起到消息缓冲&#xff0c;消息分发的作用。 消息中间件在互联网公司的使用中越来越多&#xff0c;刚才还看到新闻阿里将 RocketMQ 捐献给了 Apache&#xff0c;当然了今天的主角还…

Git-分支(branch)常用命令

分支 我们在做项目开发的时候&#xff0c;无论是软件项目还是其他机械工程项目&#xff0c;我们为了提高效率以及合理的节省时间等等原因&#xff0c;现在都不再是线性进行&#xff0c;而是将一个项目抽离出诸进行线&#xff0c;每一条线在git中我们就叫做分支&#xff0c;bran…

springboot425滑雪场管理系统(论文+源码)_kaic

摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定滑雪场管理系统的总体功能模块。然后&#xff0c;详…

好玩的汇编编译器NASM:一款基于x86架构的汇编与反汇编软件

好玩的汇编编译器NASM This is the project webpage for the Netwide Assembler (NASM), an asssembler for the x86 CPU architecture portable to nearly every modern platform, and with code generation for many platforms old and new. Netwide Assembler&#xff08;…

【AI知识】有监督学习分类任务之支持向量机

1.支持向量机概念 支持向量机&#xff08;Support Vector Machine, SVM&#xff09; 是一种有监督学习算法&#xff0c;主要用于分类任务&#xff08;也可用于回归任务&#xff0c;即支持向量回归&#xff0c;SVR&#xff09;。SVM的核心思想是找到一个最优的超平面&#xff0…

杭州乘云联合信通院发布《云计算智能化可观测性能力成熟度模型》

原文地址&#xff1a;杭州乘云联合中国信通院等单位正式发布《云计算智能化可观测性能力成熟度模型》标准 2024年12月3日&#xff0c;由全球数字经济大会组委会主办、中国信通院承办的 2024全球数字经济大会 云AI计算创新发展大会&#xff08;2024 Cloud AI Compute Ignite&…

【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说

关注作者 制造供应链的牛鞭问题与复杂问题主要是从两个方面解决&#xff0c;一是同步化供应链消减从需求到供应的放大效应&#xff0c;二是供应链细分&#xff0c;针对不同的客户、不同的需求供应的匹配策略来应对复杂性&#xff0c;更好的满足客户并以最低的总成本来实现。 对…

实时日志与发展:Elasticsearch 推出全新专用的 logsdb 索引模式

作者&#xff1a;来自 Elastic Mark Settle, George Kobar 及 Amena Siddiqi Elastic 最新发布的 logsdb 索引模式是专为日志管理优化的功能&#xff0c;旨在提升日志数据的存储效率、查询性能以及整体可用性。这个模式专注于满足现代日志处理需求&#xff0c;提供更高效的日志…

React Image Crop——在React应用中轻松实现图片裁剪功能

React Image Crop是一个用于在React应用程序中裁剪和调整图像的库。它提供了一个简单而强大的界面&#xff0c;允许用户选择和调整裁剪区域&#xff0c;并生成裁剪后的图像。 什么是React Image Crop&#xff1f; React Image Crop是一个开源的React组件&#xff0c;用于在浏览…

【HarmonyOS】鸿蒙应用实现手机摇一摇功能

【HarmonyOS】鸿蒙应用实现手机摇一摇功能 一、前言 手机摇一摇功能&#xff0c;是通过获取手机设备&#xff0c;加速度传感器接口&#xff0c;获取其中的数值&#xff0c;进行逻辑判断实现的功能。 在鸿蒙中手机设备传感器ohos.sensor (传感器)的系统API监听有以下&#xf…