在 Azure Key Vault 中,RSNULL 算法提供原始的 RSA 签名。为了使用原始RSA 签名算法生成标准SHA1 签名,您必须首先将摘要包装到将被签名的ASN.1 DigestInfo 结构中。以下示例表明:
import java.io.IOException;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.Signature;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.models.KeyBundle;
import com.microsoft.azure.keyvault.models.KeyOperationResult;
import com.microsoft.azure.keyvault.webkey.JsonWebKey;
import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
...
/**
* @param keyVaultClient An instance of Key Vault client.
* @param keyIdentifer The Key Identifier. This is the kid field of JsonWebKey structure.
* @param message The message to be signed.
*/
void sampleSHA1SignatureWithAzureKeyVault(KeyVaultClient keyVaultClient, String keyIdentifer, byte[] message) throws Throwable {
/////////////////////////////////////////
// Signs message using Azure Key Vault //
/////////////////////////////////////////
// Compute SHA1 hash:
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(message);
byte[] digest = md.digest();
// Convert SHA1 digest into ASN.1:
byte[] digestInfo = getDigestInfoForSHA1Digest(digest);
// Call Azure Key Vault to perform the signature using the server key.
// Note that we are passing the DigestInfo to RSNULL, instead of SHA1 digest.
KeyOperationResult result = keyVaultClient.sign(keyIdentifer, JsonWebKeySignatureAlgorithm.RSNULL, digestInfo);
byte[] signature = result.result();
/////////////////////////////////////////////////////////
// Verifies the signature locally, using java.security //
/////////////////////////////////////////////////////////
// Read the public key from Azure Key Vault
KeyBundle keyBundle = keyVaultClient.getKey(keyIdentifer);
// Initialize java.security instances with the Public Key and message.
KeyPair kp = keyBundle.key().toRSA(false);
Signature signImpl = Signature.getInstance("SHA1withRSA");
signImpl.initVerify(kp.getPublic());
signImpl.update(message);
// Verify the signature.
if (signImpl.verify(signature))
System.out.println("Signature was verified.");
else
System.out.println("Signature verification failed.");
}
byte[] getDigestInfoForSHA1Digest(byte[] digest) {
// Constructs an ASN.1 DigestInfo structure for the caller-specified SHA1 hash.
// ASN.1 data:
byte[] digestInfo = new byte[] { //
0x30, 0x21, // SEQUENCE DigestInfo (33 bytes) (13 of header + 20 of SHA1 digest)
0x30, 0x09, // SEQUENCE AlgorithmIdentifier (9 bytes)
0x06, 0x05, // OBJECT IDENTIFIER algorithm (5 bytes)
0x2b, 0x0e, 0x03, 0x02, 0x1a, // OID of SHA1 (1.3.14.3.2.26)
0x05, 0x00, // NUL algorithm parameters (05 00 is the DER encoding for NUL)
0x04, 0x14, // OCTET STRING digest (20 bytes)
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 // SHA1, copied below
};
System.arraycopy(digest, 0, digestInfo, 15, digest.length);
return digestInfo;
}