在 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,一经查实,立即删除!

相关文章

全局注册快捷键方案

在低代码系统中&#xff0c;快捷键是很常用的操作&#xff0c;我们如果只对绘图区域注册快捷键&#xff0c;那么焦点不在绘图区域时&#xff0c;就会失去快捷键响应&#xff0c;如果对全局拦截键盘事件&#xff0c;注册快捷键&#xff0c;那么会失去一些本应该交给系统默认快捷…

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应…

c# TaskScheduler

这里记录下 TaskScheduler 的简单用法。 使用场景&#xff1a; 使用 Task 的时候&#xff0c;大家知道用 TaskFactory.StartNew 可以用来创建一个 Task 。这里如果创建了 3 个&#xff0c;那么这3个 Task 就各自放飞直接运行了。 class Program {private static TaskFactory…

Go语言错误分类

错误的分类 在 Go 语言中&#xff0c;错误是通过实现 error 接口的类型表示的&#xff0c;但不同场景下的错误可以按性质和用途进行分类。以下是 Go 语言错误的常见分类&#xff0c;以及每类错误的解释和示例&#xff1a; 标准错误类型 标准库中定义了许多常见的错误类型&…

Couchbase的OLAP支持情况

Couchbase 是一个高性能的 NoSQL 数据库&#xff0c;主要用于在线事务处理&#xff08;OLTP&#xff09;场景&#xff0c;但它也提供了一些功能来支持在线分析处理&#xff08;OLAP&#xff09;需求。以下是 Couchbase 对 OLAP 支持的几个方面&#xff1a; 1. N1QL 查询语言 …

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

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

MeiliSearch:一款轻量级开源搜索引擎

Meilisearch 是由 Meili &#xff08;一家总部位于法国的软件开发公司&#xff09;创建的搜索引擎&#xff0c;目前在 Github 上有 47.9k stars。 Meillisearch 具备以下特色功能&#xff08;ChatGPT-4o 翻译&#xff09;&#xff1a; 混合搜索&#xff1a;结合语义搜索和全文…

随手记——conda迁移虚拟环境后不能使用Linux命令解决方案

在Ubuntu使用conda pack打包环境迁移之后发现存在以下问题&#xff1b; conda迁移环境是为了更短的的在新机器上搭建一个环境&#xff1b;我记录一下遇见的问题&#xff1b; 步骤&#xff1a; 【默认安装了conda-pack库&#xff0c;我都是安装到base虚拟环境中&#xff0c;打…

MongoDB-ObjectID 生成器

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

发愿和许愿的区别是什么?

在许多宗教和文化中&#xff0c;发愿和许愿都是人们表达内心愿望、祈求神灵保佑的重要方式。尽管这两个词在日常生活中经常被交替使用&#xff0c;但它们在含义和实践上存在一些重要的区别。本文就来详细说说发愿和许愿的区别&#xff0c;并提供相关的背景信息和建议。 1. 定义…

渗透测试工具 -- 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…

goenv go 环境配置

Golang环境配置 1. goenv工具 goenv 是一个用于管理 Go 语言版本的工具&#xff0c;类似于 Python 的 pyenv 或 Ruby 的 rbenv。不过需要注意的是&#xff0c;goenv 并不是一个官方维护的工具&#xff0c;而是一个社区项目。Go 语言本身已经提供了很好的版本管理工具&#xf…