在 SSLContext 中使用硬件支持的密钥

2024-01-23

我想在 Android 上使用硬件支持的密钥进行客户端双向 TLS。 钥匙应该通过生物识别技术解锁。

我找到了如何在 Android 上生成硬件支持的密钥对:

KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
keyGenerator.initialize(
    new KeyGenParameterSpec.Builder(myAlias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
        .setUserAuthenticationRequired(true)
        .build());
keyGenerator.generateKeyPair();

以及如何使用指纹解锁硬件支持的私钥:

FingerprintManager fingerprintManager = (FingerprintManager) this.getSystemService(Context.FINGERPRINT_SERVICE);
PrivateKey key  = (PrivateKey) keyStore.getKey(myAlias, null);
Cipher cipher = Cipher.getInstance(cipherAlgorithm, "AndroidKeyStore");
cipher.init(Cipher.DECRYPT_MODE, key);
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, authenticationCallback, null);

我还可以将 HttpClient 配置为使用客户端证书:

// I have loaded the PrivateKey privateKey and Certificate certificate from PEM files
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null);
final char pseudoSecretPassword[] = ("##" + System.currentTimeMillis()).toCharArray();
keyStore.setKeyEntry(
    PKIModule.DEFAULT_KEYSTORE_ALIAS,
    privateKey,
    pseudoSecretPassword,
    new Certificate[] {certificate}
);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, pseudoSecretPassword);
KeyManager[] keyManagers = kmf.getKeyManagers();
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
OkHttpClient newClient = new OkHttpClient.Builder()
    .sslSocketFactory(sslContext.getSocketFactory())
    .build();

但是,我没有找到一种方法来直接解锁硬件支持的私钥以供 SSLContext 使用的 KeyManager 中使用,因为解锁机制适用于加密对象而不是私钥。

如何使生物识别密钥解锁和 TLS 客户端证书在 Android 上协同工作?

Update

按照 @pedrofb 的观点,我更新了代码以生成密钥对KeyProperties.PURPOSE_SIGN and KeyProperties.DIGEST_NONE。我使用导入到服务器信任库中的 CA 签署了客户端密钥对。以及基于AndroidKeyStore创建客户端的KeyManager:

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
factory.init(keyStore, null);
KeyManager[] keyManagers = factory.getKeyManagers();
sslContext.init(keyManagers, trustManagers, new SecureRandom());

然而这失败了

W/CryptoUpcalls: Preferred provider doesn't support key:
W/System.err: java.security.InvalidKeyException: Keystore operation failed
        at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1256)
        at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1281)
        at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:54)
        at android.security.keystore.AndroidKeyStoreSignatureSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreSignatureSpiBase.java:219)
        at android.security.keystore.AndroidKeyStoreSignatureSpiBase.engineInitSign(AndroidKeyStoreSignatureSpiBase.java:99)
        at android.security.keystore.AndroidKeyStoreSignatureSpiBase.engineInitSign(AndroidKeyStoreSignatureSpiBase.java:77)
        at java.security.Signature$Delegate.init(Signature.java:1357)
        at java.security.Signature$Delegate.chooseProvider(Signature.java:1310)
        at java.security.Signature$Delegate.engineInitSign(Signature.java:1385)
        at java.security.Signature.initSign(Signature.java:679)
        at com.android.org.conscrypt.CryptoUpcalls.rawSignDigestWithPrivateKey(CryptoUpcalls.java:88)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:383)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:231)
        at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)
        at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:107)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:87)
        at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:221)
        at okhttp3.RealCall.execute(RealCall.java:81)
        at com.jemmic.secuchat.biometriccrypto.MainActivity.testMutualTLS(MainActivity.java:402)
        at com.jemmic.secuchat.biometriccrypto.MainActivity.access$300(MainActivity.java:87)
        at com.jemmic.secuchat.biometriccrypto.MainActivity$TestMutualTlsTask.doInBackground(MainActivity.java:315)
        at com.jemmic.secuchat.biometriccrypto.MainActivity$TestMutualTlsTask.doInBackground(MainActivity.java:311)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
W/System.err: Caused by: android.security.KeyStoreException: Incompatible padding mode
        at android.security.KeyStore.getKeyStoreException(KeyStore.java:1159)
        ... 43 more
W/CryptoUpcalls: Could not find provider for algorithm: NONEwithRSA

一些注意事项:

  • 密钥不受硬件支持除非设备有硬件支持。您可以使用以下命令检查密钥是否存储在安全硬件内KeyInfo.isInsideSecurityHardware().

  • TLS 需要数字签名,但您的密钥是出于加密目的而创建的。你需要改变KeyProperties.PURPOSE_ENCRYPT with KeyProperties.PURPOSE_SIGN

  • FingerprintManager 封装了使用Signature对象但它不扩展 java.security.KeyStore默认需要KeyManager

TLS需要直接管理私钥,因为TLS协议在握手过程中使用特定的算法对部分共享数据进行签名。要使用 FingerprintManager,底层加密提供程序应直接支持它。

我相信这样做可以得到相同的结果:

1-用指纹解锁所需的钥匙

2- 提供 AndroidKeyStore 给KeyManagerFactory

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null,null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, pseudoSecretPassword);

我认为这个解决方案可行,但是你您需要将证书与与服务器发送的接受 CA 列表相匹配的私钥关联起来,因此您必须使用公钥颁发证书并将其存储在与私钥关联的 android 密钥库中。

您没有提到是否要使用这种风格的解决方案,这非常复杂

如果您不打算使用证书,您可以编写自己的证书KeyManager来找回权利PrivateKey在 TLS 握手期间。看看我的答案,它与您的用例非常相似,但使用 AndroidKeyChain 而不是 AndroidKeyStore

自动或用户选择适当的客户端证书的请求 https://stackoverflow.com/questions/44929645/request-with-automatic-or-user-selection-of-appropriate-client-certificate/45035052#45035052

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 SSLContext 中使用硬件支持的密钥 的相关文章

  • 使用 google Directions API 的地图视图绘制方向 - 解码折线

    我正在尝试使用 Google 方向 API 在我的地图视图上显示方向 但我在从 JSON 响应获取数据时遇到困难 我可以获得 级别 和 点 字符串 但无法弄清楚如何将它们解码为地图上的点 任何帮助将非常感激 我有一个类可以为您解码它们 添加
  • 如何强制 Eclipse 将 xml 布局和样式显示为文本?

    我最近升级到带有 ADT 20 0 3 的 Eclipse 4 2 Juno 如果我查看旧项目中的布局或样式 Eclipse 只会向我显示其适当的基于控件的编辑器 我想编辑语法突出显示的 xml 文本 我没有找到将插件的编辑器切换到此模式的
  • 安卓定位不准确

    我正在尝试获取当前用户的位置 我试图重构我的代码以获得更好的结果 但我只是不断得到关于准确度的荒谬位置 它在 900 600 米之间 如何才能得到更好的结果 使其精度达到50m以内 这是我的代码 package com agam mapsl
  • Android 如何更改 OnTouchListener 上的按钮背景

    你好 我在 xml 中有一个按钮 我正在使用OnTouchListener在我的活动中获得button按下并释放 但问题是 当我按下按钮时背景颜色没有改变 当我延长可能的活动时OnClickListener背景正在改变 任何人都可以告诉我的
  • 如何在React Native Android中获取响应头?

    您好 我想在获取 POST 请求后获取响应标头 我尝试调试看看里面有什么response with console log response 我可以从以下位置获取响应机构responseData但我不知道如何获取标题 我想同时获得标题和正文
  • 如何检查 Android 中连接的 wifi 网络是否处于活动状态

    如何自动检查android中连接的WiFi网络上的互联网是否处于活动状态 我可以检查 wifi 是否已启用或 wifi 网络是否已连接 但我不确定如何检查互联网是否已连接 这可能吗 private boolean connectionAva
  • 使用 AES SecretKey 的 Java KeyStore setEntry()

    我目前正在 Java 中开发一个密钥处理类 特别是使用 KeyStore 我正在尝试使用 AES 实例生成 SecretKey 然后使用 setEntry 方法将其放入 KeyStore 中 我已经包含了代码的相关部分 The KS Obj
  • 在旋转时从错误的资源文件夹中提取可绘制对象

    在这里拉我的头发 因此 我正在使用一个具有多种类型的可绘制对象的应用程序 并且它们的结构如下 res Portrait resources drawable mdpi drawable hdpi drawable xhdpi Landsca
  • Android FragmentTransaction 自定义动画(未知动画师名称:Translate)

    我正在尝试让自定义动画与我的片段一起使用 我已按照在线教程进行操作 但出现以下错误 java lang RuntimeException 未知的动画师名称 翻译 动画的 XML 如下
  • Android 后台服务示例,具有交互式调用方法

    我不是 Android 方面的专家 我正在寻找一个 Android 应用程序的示例 该应用程序使用一个服务 其中有真正的功能方法 或者换句话说 一个服务可以用来做什么 我们什么时候需要它 超越简单的东西服务举例 我确信您渴望获得一些工作代码
  • 如何在 Viewpager 中禁用预加载下一页? [复制]

    这个问题在这里已经有答案了 如何在 Viewpager 中禁用页面预加载 I tried viewPager setOffscreenPageLimit 0 但它不起作用 用这个viewPager setOffscreenPageLimit
  • 有关 ListView 自定义行布局项目上的 onClick() 事件的帮助

    我有一个 ListView 其行由我格式化 每行都有 ImageView 和 TextView 的混合 我还实现了自己的适配器 并且能够通过它绘制每一行 现在 我想要这样的东西 用户单击 ImageView 不是行上的其他任何位置 但只有此
  • java.lang.NumberFormatException: Invalid int: "3546504756",这个错误是什么意思?

    我正在创建一个 Android 应用程序 并且正在从文本文件中读取一些坐标 我在用着Integer parseInt xCoordinateStringFromFile 将 X 坐标转换为整数 Y 坐标的转换方法相同 当我运行该应用程序时
  • Android:监听状态栏通知

    有没有办法在状态栏被下拉时监听通知 1 用于检测状态栏变化 您可以注册一个监听器来获取系统UI可见性变化的通知 因此 要在您的活动中注册侦听器 Detecting if the user swipe from the top down to
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • Android:AsyncTask ProgressDialog 将不会在 ActivityGroup 中打开

    我试图在轮询我的服务器时打开一个进度对话框 该类是一个 ActivityGroup 因为它嵌套在选项卡栏中 为了将视图保持在框架内 需要 ActivityGroup 这是我的 ActivityGroup 类的声明 public class
  • javafx android 中的文本字段和组合框问题

    我在简单的 javafx android 应用程序中遇到问题 问题是我使用 gradle javafxmobile plugin 在 netbeans ide 中构建了非常简单的应用程序 其中包含一些文本字段和组合框 我在 android
  • 在Android Studio gradle项目中使用NDK和STL

    我在将 stlport 链接到 Android Studio 中的 gradle 项目时遇到问题 使用 NDK 的 Eclipse Android 项目迁移到 Android Studio 该项目使用 STL 我有包含内容的 android
  • Android 中带有组的列表视图

    我有一个列表视图 每行都有一些日期和文本 我可以像 iPhone 中那样将这个 listView 分组 组之间有标题吗 在 android 中是否可能 请帮忙 即 我需要在 Listview 行之间有标题栏 以便如果我使用日期对其进行分组
  • Android 材料芯片组件崩溃应用程序。无法膨胀 xml

    Tried Chip来自两个支持库的组件 com google android support design 28 0 0 rc01和材料 com google android material material 1 0 0 rc01 堆栈

随机推荐

  • 跟踪源代码变体

    我很快就开始维护一系列包含相同嵌入式软件变体的产品 由于我已经使用 git 一年了并且非常欣赏它 所以我很可能使用它来进行源代码控制 我可以看到多种用于维护固件变体的选项 但没有一个让我太满意 您在自己的工作中应用了哪些最佳实践 我能想到的
  • 无法更改 iOS 7 (iPad) 上静态表视图单元格的背景颜色

    在 iPad 设备上运行时 我无法更改 iOS 7 上静态 UITableViewCells 的背景颜色 您可以通过以下设置轻松检查这一点 在 Xcode 5 中创建一个带有两个故事板的新通用项目 在每个故事板中 只放置一个控制器 表视图控
  • 代码 14:无法打开数据库

    我知道这个问题以前已经被问过 但是 问题是 相同的代码 用于数据库处理程序 适用于另一个应用程序 但不适用于我当前正在处理的应用程序 我什至通过检查设置中的权限来确保授予权限 这是日志猫 05 13 15 35 45 693 29696 2
  • 在 Java 8 中使用 Java 7 HashMap

    我已将 Java 应用程序更新到 Java 8 该应用程序严重依赖于 HashMap 当我运行基准测试时 我看到了不可预测的行为 对于某些输入 应用程序的运行速度比以前更快 但对于较大的输入 它的速度不断变慢 我检查了分析器 最耗时的操作是
  • 在矩阵上使用 ufunc.at

    假设我有以下 numpy 数组 gt gt gt a np zeros 10 gt gt gt a array 0 0 0 0 0 0 0 0 0 0 我可以用numpy ufunc at http docs scipy org doc n
  • Android 列表视图刷新

    我有一个 ListView 它通过数组向我显示一些数据 该数组位于另一个类中 我通过它的对象访问它 每当我通过上下文菜单从 ListView 中删除元素时 列表不会刷新 但该元素会从数组中删除 我怎样才能刷新列表来显示这一点 Code pu
  • jQuery 和 django-rest-framework-bulk:发送列表

    我需要使用 django rest Framework bulk mixins 将对象列表发送到视图 class APIPicksView mixins ListModelMixin bulk mixins BulkCreateModelM
  • 如何在散景中显示补丁的图例项

    在以下设置中 我根据基本示例创建面积图 如何自动甚至以编程方式获取输入的图例 现在我只得到带有一个项目 a 和第一种颜色的图例 from bokeh plotting import patches x2 for a in areas lis
  • 四舍五入两位小数

    double x 9 29 double y 8 69 double diff floor x y 100 0 5 100 0 这给了我 diff 为 0 6 但我需要它为 0 60 两位小数 有人可以帮我解决这个问题吗 double 的值
  • .htaccess 将所有子文件夹内容(带或不带结尾斜杠)重定向到同一子文件夹

    我想重定向以下网址 gallery image 1 gallery image 1 gallery image 2 gallery image 2 to gallery 但这比乍看起来要困难 这是来自 htaccess RewriteEng
  • Django,按日期范围内指定的月份和年份进行过滤

    我有以下型号 class Destination Deal models Model name models CharField Nombre max length 200 class Departure Date models Model
  • Javascript 事件似乎没有添加到动态生成的文本框中

    我为 JavaScript 中动态添加的文本框添加了 onkeyup javascript 但它似乎不起作用 var cell4 row insertCell 3 cell4 setAttribute align center var e3
  • JPEG 解压缩在 Windows 体系结构中不一致

    我正在使用不同版本的 Windows 的一堆计算机上测试 JPEG 解压缩 所有这些计算机都安装了 NET 4 我正在针对 NET 2 和 任何 CPU 平台目标进行编译 以下代码在不同的系统上产生不同的输出 Bitmap bmp Bitm
  • 优化“rootn(x, n)”的低精度近似

    rootn float t x int t n is a function that computes the n th root x1 n and is supported by some programming languages su
  • Windows 批处理:从文本文件设置变量

    我目前正在寻找一种通过 txt 文档中的链接在 Windows 批处理文件中设置变量的方法 例如 如果文本文件读取为 http website1 com http website2 com http website3 com 我希望可以将它
  • PHP-EWS“Soap 客户端返回状态 404”

    所以 我正在使用php ews http jamesarmes com php ews库连接到我的 Microsoft Office 365 Exchange 电子邮件帐户以阅读电子邮件 我已成功连接到它 并设法检索我需要的电子邮件列表 现
  • 可以拆分PHP配置文件php.ini吗?

    任何使用 php 的人都知道 php ini 是一个大文件 当您需要更改 ssh 时可能会让人头疼 例如我可以使用更改 nginx confinclude指令将启用站点的目录下的所有文件加载到主 nginx conf 中 所以我的问题很简单
  • 如何计算字符串的 CRC32

    如何计算 NET 中字符串的 CRC32 循环冗余校验和 这家伙似乎已经给你答案了 https damieng com blog 2006 08 08 calculate crc32 in c and net https damieng c
  • MVVM 中的数据绑定 ObservableCollection

    我有一个带有数据模板的 ListView 其中包含电影列表 它被数据绑定到 ObservableCollection 但每当我编辑 Movie Name 时 即使在我的 PropertyChangedEventHandler 中使用 Nam
  • 在 SSLContext 中使用硬件支持的密钥

    我想在 Android 上使用硬件支持的密钥进行客户端双向 TLS 钥匙应该通过生物识别技术解锁 我找到了如何在 Android 上生成硬件支持的密钥对 KeyPairGenerator keyGenerator KeyPairGenera