从 Json Web Key 获取 public key 字节数组

Obtain public key byte array from Json Web Key

我有一个包含 public 密钥信息的 Json Web 密钥,我想获取字节数组形式的 public 密钥。我的目标是最终使用 Keccak 哈希从中导出以太坊地址。从public键字节数组中获取地址的过程我明白了,但是我不知道如何获取这个字节数组。我的方案是,使用 Azure Key Vault API 生成 EC 密钥,检索密钥(JWK 格式),然后找到地址。 JWK 具有以下格式。

{
  "kid": "https: //mykeyvault.vault.azure.net/keys/testeckey/8bad08aaae514efe981eaab4e590778d",
  "kty": "EC",
  "key_ops": [
    "sign",
    "verify"
  ],
  "crv": "P-256",
  "x": "YooqHyo7hlmcrBs5lDSSUsB0axzvorjxzNl6DBZLUf0",
  "y": "NM-JrV6NTbUgILY_sBm5VgYxt1zYccCOCFtSDicSfWM"
}

我正在使用 Azure .NET SDK,我可以选择使用 Bouncy Castle for .NET 或任何 JS 库,因为项目也可以 运行 在 Node.js 环境中。如何获取 public 键的字节数组? 谢谢

回答我自己的问题以防其他人需要这个。 我也写了一篇关于这个的文章,希望有人觉得它有用。

https://tmarkovski.github.io/eth-azure/keyvault-part1/

最初,我生成的密钥类型不正确。我能够通过连接来自 JWK 的 X 和 Y 数组来生成密钥。这是我在 F# 中使用的示例代码。它使用 BouncyCastle 作为 Keccak 哈希函数。 需要注意的重要一点是 "EC-HSM" 键类型的使用。这是 Key Vault 的 Premium SKU 的一部分,只有这种类型支持 SECP256K1 曲线,否则如果使用 "EC" 密钥类型会引发异常。

open Microsoft.Azure.KeyVault
open System.Threading.Tasks
open System
open Microsoft.IdentityModel.Clients.ActiveDirectory
open Microsoft.Azure.KeyVault.Models
open Microsoft.Azure.KeyVault.WebKey
open Org.BouncyCastle.Crypto.Digests
open Org.BouncyCastle.Crypto

/// Implements an extension method that overloads the standard
/// 'Bind' of the 'async' builder. The new overload awaits on 
/// a standard .NET task
type AsyncBuilder with
  member __.Bind(t:Task<'T>, f:'T -> Async<'R>) : Async<'R>  = 
    async.Bind(Async.AwaitTask t, f)

let vaultUri = "https://__mykeyvault__.vault.azure.net/"
let clientId = "..."
let clientSecret = "..."

type AuthenticationCallback = KeyVaultClient.AuthenticationCallback

let getAccessToken (authority:string) (resource:string) (scope:string) =    
    let clientCredential = new ClientCredential(clientId, clientSecret)
    let context = new AuthenticationContext(authority, TokenCache.DefaultShared)
    async {
        let! result = context.AcquireTokenAsync(resource, clientCredential)
        return result.AccessToken;
    } |> Async.StartAsTask

let client = new KeyVaultClient(new KeyVaultCredential(new AuthenticationCallback(getAccessToken)))

let createKey name =
    let keyParams = new NewKeyParameters()
    keyParams.Kty <- "EC-HSM"
    keyParams.CurveName <- EcKey.SECP256K1

    async {
        let! result = client.CreateKeyAsync(vaultUri, name, keyParams)
        return result
    } |> Async.RunSynchronously

let getKey name = 
    async {
        let! result = client.GetKeyAsync(vaultBaseUrl = vaultUri, keyName = name)
        return result
    } |> Async.RunSynchronously

let getPubKey (jwk:KeyBundle) = 
     Array.concat [| jwk.Key.X; jwk.Key.Y |]

let hash (digest:IDigest) data =
    digest.Reset()
    digest.BlockUpdate(data, 0, data.Length)

    let a = digest.GetDigestSize() |> Array.zeroCreate
    digest.DoFinal(a, 0) |> ignore
    a

let toHex (x:byte) = x.ToString("x2")

let getAddress pubKey =
    pubKey
    |> hash (new KeccakDigest(256))
    |> Array.map toHex
    |> Array.skip 12
    |> String.Concat
    |> (+) "0x"


createKey "testEcKey"
|> getPubKey
|> getAddress
|> Console.WriteLine

// 0x51e4370152c132d307c302d8146c63ca6bf41167