---
# System prepended metadata

title: How to Securely Store Signing Keys in Wallets
tags: [SoulWallet]

---

### [EN]

We all know that in digital wallets, signing keys represent ownership of the wallet, and every "self-custody wallet" developer strives to make the wallet capable of securely storing the keys. However, many may not be aware that the security level of the same wallet on different devices can vary.

1. Native Wallet Applications
   - iOS: Developers can use [passkey](https://developer.apple.com/passkeys/) and [keychain](https://developer.apple.com/documentation/security/keychain_services/) to generate or store keys (using passkey means Ethereum accounts must support secp256r1 signature verification, which currently requires more than 300,000 gas).
   - Android: Developers can use [keystore](https://developer.android.com/training/articles/keystore) to store keys.
   - Windows: Passkey via Windows Hello and [Credential Manager](https://learn.microsoft.com/en-us/windows/win32/secauthn/credentials-management) can be used for key management.
   - Mac: Developers can use [passkey](https://developer.apple.com/passkeys/) and [keychain](https://developer.apple.com/documentation/security/keychain_services/) to store keys.

   This is especially important for devices that support Hardware Security Modules (HSM).

2. Web Wallets & Browser Plugin Wallets

   Unfortunately, there is no keychain-like support in the web environment, which means developers only have the option of using passkey. However, on-chain verification of passkey (secp256r1) signatures requires over 200,000 gas, which may discourage many users from using it, even in Layer 2 (though this can be improved later by introducing precompiled contracts).

   But "modern browsers" provide us with the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API#browser_compatibility)! Besides offering high-performance encryption algorithms, the most important feature is the support for [CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)! Let's see how CryptoKey can enhance the security of private key management:

   1. By setting `extractable=false` through `window.crypto.subtle.importKey` and importing the private key, a CryptoKey instance will be generated. [Example](https://github.com/proofofsoulprotocol/soulwalletlib/blob/0292d00bd5a0300183c5901686a2febf4fdda6d5/packages/soulwallet-keyvault/src/crypto-browser.ts#L52)
   2. At this point, CryptoKey can only be used for encryption, decryption, signing, and signature verification, and the internal private key cannot be exported (unless there are serious security vulnerabilities in the browser). If interested, you can find relevant implementations in the [Chromium project](https://github.com/chromium/chromium/blob/117.0.5914.1/components/webcrypto/webcrypto_impl.cc).
   3. Even though the browser provides the CryptoKey extractable=false feature, careful coding is still required to minimize the possibility of private key leakage (e.g., during the process of importing the decrypted private key into CryptoKey).
   4. Additionally, Web Crypto API does not provide support for anti-brute force algorithms like Argon2 and Scrypt. For security, we need to introduce high-performance Argon2 and Scrypt libraries in wasm format in the web page, so that we can offer users a choice of higher-level anti-brute force algorithms when unlocking their wallets without significantly reducing user experience.

   ...

   These factors, among others, are why we chose to develop our own software package for private key management. [@soulwallet/keyvault](https://github.com/proofofsoulprotocol/soulwalletlib/tree/develop/packages/soulwallet-keyvault) is still in its early development stage, and we welcome anyone to contribute code or provide feedback.
   
---
   
   
### [zh-CN]
我们都知道在数字钱包中 签名密钥意味着钱包所有权，每个‘自托管钱包’开发者都竭尽所能地让钱包能够更加安全地保管密钥，而且很多人可能没有意识到对于多数用户即使同一个钱包在不同设备端的安全性的上限也是不同的。

1. 独立的原生钱包应用
   1. iOS : 可以使用 [passkey](https://developer.apple.com/passkeys/) ，[keychain](https://developer.apple.com/documentation/security/keychain_services/) 来生成或者保管密钥 (如果使用 passkey 则意味着 以太坊账户必须支持 secp256r1 签名验证，当前这个验证过程可能需要超过30万 gas )
   2. Android: 可以使用 [keystore](https://developer.android.com/training/articles/keystore) 来保管密钥
   3. Window : 可以使用 passkey via windows hello, [Credential Manager](https://learn.microsoft.com/en-us/windows/win32/secauthn/credentials-management) 来进行密钥的管理
   4. Mac：可以使用 [passkey](https://developer.apple.com/passkeys/) ，[keychain](https://developer.apple.com/documentation/security/keychain_services/) 来保管密钥

   尤其是在支持硬件安全模块（HSM）的设备中。

2. 网页钱包  & 浏览器插件钱包

   不幸的是在web端没有类似 keychain 的支持，意味着开发者可选的仅仅是 passkey，但是在链上验证 passkey (secp256r1) 的签名需要超过 20 万gas，这意味着即使是在 Layer 2，很多用户都可能因为成本问题而放弃（当然后面可以通过引入预编译合约来改善成本）。

   但是‘现代化浏览器’给我们提供了 [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API#browser_compatibility) ! 除了能给我们提供高性能的加密算法之外，最重要的是提供了 [CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) 支持！我们来看一下如何使用 CryptoKey 来提升私钥管理的安全性：

   1. 通过 `window.crypto.subtle.importKey`设置 `extractable=false` 并导入私钥后，会生成一个CryptoKey 实例，[示例](https://github.com/proofofsoulprotocol/soulwalletlib/blob/0292d00bd5a0300183c5901686a2febf4fdda6d5/packages/soulwallet-keyvault/src/crypto-browser.ts#L52)
   2. 此时的 Crypto 仅仅能够用来 加密、解密、签名、验证签名，而无法导出内部的私钥(除非浏览器存在相关严重的安全漏洞)，如果有兴趣可以在 [chromium项目](https://github.com/chromium/chromium/blob/117.0.5914.1/components/webcrypto/webcrypto_impl.cc)中找到相关的实现。
   3. 即使浏览器提供了 CryptoKey extractable=false 特性，但是为了保证安全 我们依旧需要仔细的进行相关编码，确保私钥被泄漏的可能性最低 (例如把解密后的私钥导入到 CryptoKey 的过程时)。
   4. 另外 Web Crypto API 并未提供 Argon2 、Scrypt 等抗暴力破解算法的支持，为了安全我们需要在网页中引入 wasm 的高性能  Argon2 、Scrypt 库，这样我们就可以让用户解锁钱包时在不明显降低用户体验的同时选择更高等级的抗暴力破解算法。

   ...

   包括但是不限于以上因素是我们选择自己编写软件包来进行私钥管理的原因, [@soulwallet/keyvault](https://github.com/proofofsoulprotocol/soulwalletlib/tree/develop/packages/soulwallet-keyvault) 还处于早期的开发阶段，欢迎任何人提供代码或者反馈