using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
namespace SampleCryptographicEngine
{
sealed partial class CryptographicEngineApp : Application
{
// Initialize a static nonce value.
static byte[] NonceBytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public CryptographicEngineApp()
{
// Initialize the application.
this.InitializeComponent();
/////////////////////////////////////////////////////////////////////////////
// Initialize input and output variables.
String strMsg = String.Empty; // Message string
String strAlgName = String.Empty; // Algorithm name
UInt32 keyLength = 0; // Length of key
BinaryStringEncoding encoding; // Binary encoding type
IBuffer iv; // Initialization vector
CryptographicKey key; // Symmetric Key
IBuffer buffNonce; // Buffer containing the nonce
IBuffer buffMsg; // Buffer containing the message
CryptographicKey hmacKey; // HMAC key
/////////////////////////////////////////////////////////////////////////////
// Perform symmetric encryption and decryption.
strMsg = "1234567812345678";
strAlgName = SymmetricAlgorithmNames.AesCbc;
keyLength = 32;
IBuffer buffEncrypted = this.SampleCipherEncryption(
strMsg,
strAlgName,
keyLength,
out encoding,
out iv,
out key);
this.SampleCipherDecryption(
strAlgName,
buffEncrypted,
iv,
encoding,
key);
/////////////////////////////////////////////////////////////////////////////
// Encrypt and decrypt authenticated data.
strMsg = "This is a message.";
strAlgName = SymmetricAlgorithmNames.AesGcm;
keyLength = 32;
EncryptedAndAuthenticatedData objEncrypted = this.AuthenticatedEncryption(
strMsg,
strAlgName,
keyLength,
out encoding,
out buffNonce,
out key);
this.AuthenticatedDecryption(
strAlgName,
key,
objEncrypted,
encoding,
buffNonce);
/////////////////////////////////////////////////////////////////////////////
// Derive Key material (Pbkdf2).
strAlgName = KeyDerivationAlgorithmNames.Pbkdf2Sha256;
keyLength = 32;
String strHexKey = this.SampleDeriveFromPbkdf(
strAlgName,
keyLength);
/////////////////////////////////////////////////////////////////////////////
// Demonstrate signing and signature verification.
strMsg = "This is a message to be signed.";
strAlgName = MacAlgorithmNames.HmacSha384;
IBuffer buffHMAC = this.SampleCreateHMAC(
strMsg,
strAlgName,
out buffMsg,
out hmacKey);
this.SampleVerifyHMAC(
buffMsg,
hmacKey,
buffHMAC);
}
public IBuffer SampleCipherEncryption(
String strMsg,
String strAlgName,
UInt32 keyLength,
out BinaryStringEncoding encoding,
out IBuffer iv,
out CryptographicKey key)
{
// Initialize the initialization vector.
iv = null;
// Initialize the binary encoding value.
encoding = BinaryStringEncoding.Utf8;
// Create a buffer that contains the encoded message to be encrypted.
IBuffer buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);
// Open a symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
// Determine whether the message length is a multiple of the block length.
// This is not necessary for PKCS #7 algorithms which automatically pad the
// message to an appropriate length.
if (!strAlgName.Contains("PKCS7"))
{
if ((buffMsg.Length % objAlg.BlockLength) != 0)
{
throw new Exception("Message buffer length must be multiple of block length.");
}
}
// Create a symmetric key.
IBuffer keyMaterial = CryptographicBuffer.GenerateRandom(keyLength);
key = objAlg.CreateSymmetricKey(keyMaterial);
// CBC algorithms require an initialization vector. Here, a random
// number is used for the vector.
if (strAlgName.Contains("CBC"))
{
iv = CryptographicBuffer.GenerateRandom(objAlg.BlockLength);
}
// Encrypt the data and return.
IBuffer buffEncrypt = CryptographicEngine.Encrypt(key, buffMsg, iv);
return buffEncrypt;
}
public void SampleCipherDecryption(
String strAlgName,
IBuffer buffEncrypt,
IBuffer iv,
BinaryStringEncoding encoding,
CryptographicKey key)
{
// Declare a buffer to contain the decrypted data.
IBuffer buffDecrypted;
// Open an symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
// The input key must be securely shared between the sender of the encrypted message
// and the recipient. The initialization vector must also be shared but does not
// need to be shared in a secure manner. If the sender encodes a message string
// to a buffer, the binary encoding method must also be shared with the recipient.
buffDecrypted = CryptographicEngine.Decrypt(key, buffEncrypt, iv);
// Convert the decrypted buffer to a string (for display). If the sender created the
// original message buffer from a string, the sender must tell the recipient what
// BinaryStringEncoding value was used. Here, BinaryStringEncoding.Utf8 is used to
// convert the message to a buffer before encryption and to convert the decrypted
// buffer back to the original plaintext.
String strDecrypted = CryptographicBuffer.ConvertBinaryToString(encoding, buffDecrypted);
}
public EncryptedAndAuthenticatedData AuthenticatedEncryption(
String strMsg,
String strAlgName,
UInt32 keyLength,
out BinaryStringEncoding encoding,
out IBuffer buffNonce,
out CryptographicKey key)
{
// Open a SymmetricKeyAlgorithmProvider object for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlgProv = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a buffer that contains the data to be encrypted.
encoding = BinaryStringEncoding.Utf8;
IBuffer buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);
// Generate a symmetric key.
IBuffer keyMaterial = CryptographicBuffer.GenerateRandom(keyLength);
key = objAlgProv.CreateSymmetricKey(keyMaterial);
// Generate a new nonce value.
buffNonce = GetNonce();
// Encrypt and authenticate the message.
EncryptedAndAuthenticatedData objEncrypted = CryptographicEngine.EncryptAndAuthenticate(
key,
buffMsg,
buffNonce,
null);
return objEncrypted;
}
IBuffer GetNonce()
{
// Security best practises require that an ecryption operation not
// be called more than once with the same nonce for the same key.
// A nonce value can be predictable, but must be unique for each
// secure session.
NonceBytes[0]++;
for (int i = 0; i < NonceBytes.Length - 1; i++)
{
if (NonceBytes[i] == 255)
{
NonceBytes[i + 1]++;
}
}
return CryptographicBuffer.CreateFromByteArray(NonceBytes);
}
public void AuthenticatedDecryption(
String strAlgName,
CryptographicKey key,
EncryptedAndAuthenticatedData objEncrypted,
BinaryStringEncoding encoding,
IBuffer buffNonce)
{
// Declare a buffer to contain the decrypted data.
IBuffer buffDecrypted;
// Open a SymmetricKeyAlgorithmProvider object for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlgProv = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
// The input key must be securely shared between the sender of the encrypted message
// and the recipient. The nonce must also be shared but does not need to be shared
// in a secure manner. If the sender encodes the message string to a buffer, the
// binary encoding method must also be shared with the recipient.
// The recipient uses the DecryptAndAuthenticate() method as follows to decrypt the
// message, authenticate it, and verify that it has not been altered in transit.
buffDecrypted = CryptographicEngine.DecryptAndAuthenticate(
key,
objEncrypted.EncryptedData,
buffNonce,
objEncrypted.AuthenticationTag,
null);
// Convert the decrypted buffer to a string (for display). If the sender created the
// original message buffer from a string, the sender must tell the recipient what
// BinaryStringEncoding value was used. Here, BinaryStringEncoding.Utf8 is used to
// convert the message to a buffer before encryption and to convert the decrypted
// buffer back to the original plaintext.
String strDecrypted = CryptographicBuffer.ConvertBinaryToString(encoding, buffDecrypted);
}
public String SampleDeriveFromPbkdf(
String strAlgName,
UInt32 targetSize)
{
// Open the specified algorithm.
KeyDerivationAlgorithmProvider objKdfProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a buffer that contains the secret used during derivation.
String strSecret = "MyPassword";
IBuffer buffSecret = CryptographicBuffer.ConvertStringToBinary(strSecret, BinaryStringEncoding.Utf8);
// Create a random salt value.
IBuffer buffSalt = CryptographicBuffer.GenerateRandom(32);
// Specify the number of iterations to be used during derivation.
UInt32 iterationCount = 10000;
// Create the derivation parameters.
KeyDerivationParameters pbkdf2Params = KeyDerivationParameters.BuildForPbkdf2(buffSalt, iterationCount);
// Create a key from the secret value.
CryptographicKey keyOriginal = objKdfProv.CreateKey(buffSecret);
// Derive a key based on the original key and the derivation parameters.
IBuffer keyDerived = CryptographicEngine.DeriveKeyMaterial(
keyOriginal,
pbkdf2Params,
targetSize);
// Encode the key to a hexadecimal value (for display)
String strKeyHex = CryptographicBuffer.EncodeToHexString(keyDerived);
// Return the encoded string
return strKeyHex;
}
public IBuffer SampleCreateHMAC(
String strMsg,
String strAlgName,
out IBuffer buffMsg,
out CryptographicKey hmacKey)
{
// Create a MacAlgorithmProvider object for the specified algorithm.
MacAlgorithmProvider objMacProv = MacAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a buffer that contains the message to be signed.
BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);
// Create a key to be signed with the message.
IBuffer buffKeyMaterial = CryptographicBuffer.GenerateRandom(objMacProv.MacLength);
hmacKey = objMacProv.CreateKey(buffKeyMaterial);
// Sign the key and message together.
IBuffer buffHMAC = CryptographicEngine.Sign(hmacKey, buffMsg);
// Verify that the HMAC length is correct for the selected algorithm
if (buffHMAC.Length != objMacProv.MacLength)
{
throw new Exception("Error computing digest");
}
// Return the HMAC.
return buffHMAC;
}
public void SampleVerifyHMAC(
IBuffer buffMsg,
CryptographicKey hmacKey,
IBuffer buffHMAC)
{
// The input key must be securely shared between the sender of the HMAC and
// the recipient. The recipient uses the CryptographicEngine.VerifySignature()
// method as follows to verify that the message has not been altered in transit.
Boolean IsAuthenticated = CryptographicEngine.VerifySignature(hmacKey, buffMsg, buffHMAC);
if (!IsAuthenticated)
{
throw new Exception("The message cannot be verified.");
}
}
}
}