Question

Martin00 on Thu, 29 Sep 2016 13:22:45


Hi,

I have a data payload supplied by an Azure api app. This payload is signed by the app, using a KeyVaultClient SignAsync method.

This data is saved by the app client and should be usable offline.

The key I used for signing was generated with

$key = Add-AzureKeyVaultKey -VaultName 'ContosoKeyVault' -Name 'ContosoFirstKey' -Destination 'Software'

from Add a key or secret to the key vault

NB About Keys and Secrets referenced from the cmdlet help is no longer available

I have some assumptions and questions which I'd like to clarify/ask  first:

Keys in KeyVault may in fact be(/are always?) key pairs. I presume this because KeyVaultClient.GetKeyAsync says "Retrieves the public portion of a key plus its attributes ".

In that case, if I already have a key pair, in the shape of a pfx file, why is the recommended approach to uploading this to treat it as a secret, as per How to store pfx certificate in Azure Key Vault ?

I haven't found a clear statement of what KeyVault means by a Key, and what it means by a Secret. For the avoidance of doubt, these definitions would be good. I also think it would be worth making it much clearer what operations can be done with each object. This would help the decision on when to use a Key and when to use a Secret.

Somewhere I read/heard (in video?) that once something is put in the vault, it can't be retrieved again. This makes good security sense, and explains why operations such as Sign and Verify are provided by KeyVaultClient, except for the implied public key, which should be accessible, and apparently is.

Anyway, given these points, I want to be able to verify a signature using the public key offline.

Previously I've used an RSACryptoServiceProvider to Verify signatures offline, but it uses a different level of abstraction - by combining generation of the hash/digest as well as signing it; where as KeyVaultClient works with the digest directly. - Makes sense given it's a cloud service. So I know what hash algorithm I used in the cloud to generate the digest, but not what algorithm was used to sign the hash. How can I tell?

Am I on the right track here? Have I made some wrong assumptions? I'm using Microsoft.Azure.KeyVault v2.0.2preview. I appreciate this stuff is a work in progress, but never the less it would nice to join it up some more.

Update: the page About keys, secrets, and certificates published yesterday looks like it might answer some of my questions

Thanks

Martin




Sponsored



Replies

Martin00 on Thu, 29 Sep 2016 15:11:28


So I thought I would have a go at converting the JsonWebKey.Key property to xml of a form that could be used by RSACryptoServiceProvider.FromXmlString. Whilst superficially it seemed they might be semantically equivalent, in fact that don't line up very well. the following table indicates the attribute comparison, including which sample data was populated. Doesn't look very encouraging to me. The question stands. How to use a public key obtained from KeyVault to Verify a digest offline.

Thanks

Martin 

RSAKeyValue

JsonWebKey

 Populated   (RSA/Json)  

Modulus

 N

 R

Exponent

 E

 R,J

P

P

 R

Q

Q

 R

DP

DP

DQ

DQ

 R

InverseQ

 

 R

D

D

 R

 

E

 

 

K

 

 

N

 J

Looks like this spec will help me https://tools.ietf.org/html/rfc7518 section 6.3

Rahul P Nath on Tue, 11 Oct 2016 03:53:45


Hi Martin,

I had used the below code snippet a while back to verify signatures

using (var rsa = new RSACryptoServiceProvider())
{
    var p = new RSAParameters() { Modulus = key.Key.N, Exponent = key.Key.E };
    rsa.ImportParameters(p);
    var byteData = Encoding.Unicode.GetBytes(textToEncrypt);

    // Encrypt and Decrypt
    var encryptedText = rsa.Encrypt(byteData, true);
    var decryptedData = await keyClient.DecryptDataAsync(keyIdentifier, "RSA_OAEP", encryptedText);
    var decryptedText = Encoding.Unicode.GetString(decryptedData.Result);

    // Sign and Verify
    var hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);
    var signature = await keyClient.SignAsync(keyIdentifier, "RS256", digest);
    var isVerified = rsa.VerifyHash(digest, "Sha256", signature.Result);

Between you can import a pfx file as a key into the Key Vault. It is upto you and the specific use case to determine whether to have that as a Key or a Secret. When uploading it as a Key, you cannot get back the private portion from the Key vault after that (unless from the original pfx file you used). Private portions of the key does not flow out of the Vault. But when having it as a secret you can recreate back the pfx file back again. 

Rahul P Nath on Tue, 22 Nov 2016 18:55:47


Here (Azure Key Vault: Digital Signatures and Offline Verification) is a detailed post on how to achieve this using the code snippet above.