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."); } } } }