0

I have a Json Web Key that contains public key information and I'd like to derive ethereum address from it. I understand the process of getting the address by hashing using Keccak from the public key byte array, but I don't know how to obtain this byte array. My scenario is, generate EC key using Azure Key Vault API, retrieve the key (JWK format) and then find the address. The JWK has the following format.

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

I'm using the Azure .NET SDK and I have the option to use Bouncy Castle for .NET or any JS library, since project can also run in a Node.js environment. How can I obtain the byte array of the public key? Thank you

  • 1
    One issue with your example is that it uses a curve P-256, which is not the same curve that the used in Ethereum secp256k1. The public key are not compatible between them since they satisfy different equations. If you can generate a valid secp256k1 JWK it should be easy to convert the x, y coordinates in base 64 to the format expected in the algorithm used to generate an Ethereum address, ie uncompressed key. – Ismael Jan 27 '18 at 4:35
  • 1
    Thank you @Ismael. I have since resolved this issue (I think). You're right, "EC" key won't work, I had to use "EC-HSM" key type which supports secp256k1 curve. I was able to generate the public key by concatenating 0x04 + x + y byte arrays of they JWK key result to get the public key. Then Keccak hash into hex string and take last 40 chars for the address. I guess I should post my work so others can benefit. – Tomislav Markovski Jan 28 '18 at 20:41
  • Correction to my above comment, the pubKey is just a combination of X and Y, without 0x04 at the start. Verified this against eth utils. – Tomislav Markovski Jan 30 '18 at 0:15
1

As Ismail pointed out in the comments, I was generating the incorrect key type. Additionally, I was able to generate the key by concatenating the X and Y arrays from JWK. Here's my sample code I was playing with in F#. It uses BouncyCastle for the Keccak hash function. Important thing to note is the use of "EC-HSM" key type. This is part of the Premium SKU for Key Vault and only this type supports SECP256K1 curve, otherwise throws an exception if using "EC" key type.

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

I also wrote a little article about this process here https://tmarkovski.github.io/eth-azure/keyvault-part1/

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.