/// <summary> /// Gets the file format of the specified stream based on file signature. /// </summary> /// <param name="buffer">The signature bytes buffer.</param> /// <returns>The detected database file format.</returns> private static FileFormats CheckSignature(IBuffer buffer) { if (buffer == null) { throw new ArgumentNullException("buffer"); } // KeePass 1.x var oldSignature = CryptographicBuffer .DecodeFromHexString("03D9A29A65FB4BB5"); if (CryptographicBuffer.Compare(buffer, oldSignature)) { return(FileFormats.KeePass1x); } // KeePass 2.x pre-release var preRelease = CryptographicBuffer .DecodeFromHexString("03D9A29A66FB4BB5"); if (CryptographicBuffer.Compare(buffer, preRelease)) { return(FileFormats.OldVersion); } // KeePass 2.x var current = CryptographicBuffer .DecodeFromHexString("03D9A29A67FB4BB5"); if (!CryptographicBuffer.Compare(buffer, current)) { return(FileFormats.NotSupported); } return(FileFormats.Supported); }
public async Task StoredDataIsOverwritable() { Assert.IsNull( await this.credentialProvider.GetRawKeyAsync(this.storedCandidate.FileName), "StoredCandidate should not be stored yet" ); byte[] overwriteData = Enumerable.Range(0, 256).Reverse().Select(i => (byte)i).ToArray(); IBuffer overwriteBuffer = CryptographicBuffer.CreateFromByteArray(overwriteData); Assert.IsTrue(await this.credentialProvider.TryStoreRawKeyAsync(this.storedCandidate.FileName, this.mockPasswordBuffer)); Assert.IsTrue( await this.credentialProvider.TryStoreRawKeyAsync(this.storedCandidate.FileName, overwriteBuffer), "Storing data twice for a database should be fine" ); IBuffer retrievedData = await this.credentialProvider.GetRawKeyAsync(this.storedCandidate.FileName); Assert.IsNotNull(retrievedData); Assert.IsTrue( CryptographicBuffer.Compare(overwriteBuffer, retrievedData), "The retrieved data should be what was stored most recently for the database" ); }
/// <summary> /// This is the click handler for the 'RunSample' button. It is responsible for executing the sample code. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RunSample_Click(object sender, RoutedEventArgs e) { String algName = AlgorithmNames.SelectionBoxItem.ToString(); UInt32 keySize = UInt32.Parse(KeySizes.SelectionBoxItem.ToString()); Scenario5Text.Text = ""; IBuffer encrypted; IBuffer decrypted; IBuffer buffer; IBuffer iv = null; String blockCookie = "1234567812345678"; // 16 bytes // Open the algorithm provider for the algorithm specified on input. SymmetricKeyAlgorithmProvider Algorithm = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algName); Scenario5Text.Text += "\n*** Sample Cipher Encryption\n"; Scenario5Text.Text += " Algorithm Name: " + Algorithm.AlgorithmName + "\n"; Scenario5Text.Text += " Key Size: " + keySize + "\n"; Scenario5Text.Text += " Block length: " + Algorithm.BlockLength + "\n"; // Generate a symmetric key. IBuffer keymaterial = CryptographicBuffer.GenerateRandom((keySize + 7) / 8); CryptographicKey key; try { key = Algorithm.CreateSymmetricKey(keymaterial); } catch (ArgumentException ex) { Scenario5Text.Text += ex.Message + "\n"; Scenario5Text.Text += "An invalid key size was selected for the given algorithm.\n"; return; } // CBC mode needs Initialization vector, here just random data. // IV property will be set on "Encrypted". if (algName.Contains("CBC")) { iv = CryptographicBuffer.GenerateRandom(Algorithm.BlockLength); } // Set the data to encrypt. buffer = CryptographicBuffer.ConvertStringToBinary(blockCookie, BinaryStringEncoding.Utf8); // Encrypt and create an authenticated tag. encrypted = Windows.Security.Cryptography.Core.CryptographicEngine.Encrypt(key, buffer, iv); Scenario5Text.Text += " Plain text: " + buffer.Length + " bytes\n"; Scenario5Text.Text += " Encrypted: " + encrypted.Length + " bytes\n"; // Create another instance of the key from the same material. CryptographicKey key2 = Algorithm.CreateSymmetricKey(keymaterial); if (key.KeySize != key2.KeySize) { Scenario5Text.Text += "CreateSymmetricKey failed! The imported key's size did not match the original's!"; return; } // Decrypt and verify the authenticated tag. decrypted = Windows.Security.Cryptography.Core.CryptographicEngine.Decrypt(key2, encrypted, iv); if (!CryptographicBuffer.Compare(decrypted, buffer)) { Scenario5Text.Text += "Decrypted does not match original!"; return; } }
/// <summary> /// Reads the specified hashed block stream into a memory stream. /// </summary> /// <param name="input">The hashed block stream.</param> /// <returns>The de-hashed stream.</returns> public static async Task <Stream> Read(IInputStream input) { if (input == null) { throw new ArgumentNullException("input"); } var blockIndex = 0; var result = new MemoryStream(); var hash = WindowsRuntimeBuffer.Create(32); var reader = new DataReader(input) { ByteOrder = ByteOrder.LittleEndian, }; var sha = HashAlgorithmProvider .OpenAlgorithm(HashAlgorithmNames.Sha256); try { while (true) { // Detect end of file var read = await reader.LoadAsync(4); if (read == 0) { break; } // Verify block index var index = reader.ReadInt32(); if (index != blockIndex) { throw new InvalidDataException(string.Format( "Wrong block ID detected, expected: {0}, actual: {1}", blockIndex, index)); } blockIndex++; // Block hash hash = await input.ReadAsync(hash, 32); if (hash.Length != 32) { throw new InvalidDataException( "Data corruption detected (truncated data)"); } read = await reader.LoadAsync(4); if (read != 4) { throw new InvalidDataException( "Data corruption detected (truncated data)"); } // Validate block size (< 10MB) var blockSize = reader.ReadInt32(); if (blockSize == 0) { // Terminator block var isTerminator = hash .ToArray() .All(x => x == 0); if (!isTerminator) { throw new InvalidDataException( "Data corruption detected (invalid hash for terminator block)"); } break; } if (0 > blockSize || blockSize > 10485760) { throw new InvalidDataException( "Data corruption detected (truncated data)"); } // Check data truncate var loaded = await reader.LoadAsync((uint)blockSize); if (loaded < blockSize) { throw new InvalidDataException( "Data corruption detected (truncated data)"); } var buffer = reader.ReadBuffer((uint)blockSize); // Verify block integrity var actual = sha.HashData(buffer); if (!CryptographicBuffer.Compare(hash, actual)) { throw new InvalidDataException( "Data corruption detected (content corrupted)"); } await result.WriteAsync(buffer.ToArray(), 0, (int)buffer.Length); } result.Position = 0; return(result); } catch { result.Dispose(); throw; } }
/// <summary> /// This is the click handler for the 'RunSample' button. It is responsible for executing the sample code. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RunEncryption_Click(object sender, RoutedEventArgs e) { EncryptDecryptText.Text = ""; IBuffer encrypted; IBuffer decrypted; IBuffer iv = null; IBuffer data; IBuffer nonce; String algName = AlgorithmNames.SelectionBoxItem.ToString(); CryptographicKey key = null; if (bSymAlgs.IsChecked.Value || bAuthEncrypt.IsChecked.Value) { key = GenerateSymmetricKey(); } else { key = GenerateAsymmetricKey(); } data = GenearetData(); if ((bool)bAuthEncrypt.IsChecked) { nonce = GetNonce(); EncryptedAndAuthenticatedData encryptedData = CryptographicEngine.EncryptAndAuthenticate(key, data, nonce, null); EncryptDecryptText.Text += " Plain text: " + data.Length + " bytes\n"; EncryptDecryptText.Text += " Encrypted: " + encryptedData.EncryptedData.Length + " bytes\n"; EncryptDecryptText.Text += " AuthTag: " + encryptedData.AuthenticationTag.Length + " bytes\n"; decrypted = CryptographicEngine.DecryptAndAuthenticate(key, encryptedData.EncryptedData, nonce, encryptedData.AuthenticationTag, null); if (!CryptographicBuffer.Compare(decrypted, data)) { EncryptDecryptText.Text += "Decrypted does not match original!"; return; } } else { // CBC mode needs Initialization vector, here just random data. // IV property will be set on "Encrypted". if (algName.Contains("CBC")) { SymmetricKeyAlgorithmProvider algorithm = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algName); iv = CryptographicBuffer.GenerateRandom(algorithm.BlockLength); } // Encrypt the data. try { encrypted = CryptographicEngine.Encrypt(key, data, iv); } catch (ArgumentException ex) { EncryptDecryptText.Text += ex.Message + "\n"; EncryptDecryptText.Text += "An invalid key size was selected for the given algorithm.\n"; return; } EncryptDecryptText.Text += " Plain text: " + data.Length + " bytes\n"; EncryptDecryptText.Text += " Encrypted: " + encrypted.Length + " bytes\n"; // Decrypt the data. decrypted = CryptographicEngine.Decrypt(key, encrypted, iv); if (!CryptographicBuffer.Compare(decrypted, data)) { EncryptDecryptText.Text += "Decrypted data does not match original!"; return; } } }
public async void SampleDataProtectionStream(String descriptor) { EncryptDecryptText.Text += "*** Sample Stream Data Protection for " + descriptor + " ***\n"; IBuffer data = CryptographicBuffer.GenerateRandom(10000); DataReader reader1, reader2; IBuffer buff1, buff2; DataProtectionProvider Provider = new DataProtectionProvider(descriptor); InMemoryRandomAccessStream originalData = new InMemoryRandomAccessStream(); //Populate the new memory stream IOutputStream outputStream = originalData.GetOutputStreamAt(0); DataWriter writer = new DataWriter(outputStream); writer.WriteBuffer(data); await writer.StoreAsync(); await outputStream.FlushAsync(); //open new memory stream for read IInputStream source = originalData.GetInputStreamAt(0); //Open the output memory stream InMemoryRandomAccessStream protectedData = new InMemoryRandomAccessStream(); IOutputStream dest = protectedData.GetOutputStreamAt(0); // Protect await Provider.ProtectStreamAsync(source, dest); //Flush the output if (await dest.FlushAsync()) { EncryptDecryptText.Text += " Protected output was successfully flushed\n"; } //Verify the protected data does not match the original reader1 = new DataReader(originalData.GetInputStreamAt(0)); reader2 = new DataReader(protectedData.GetInputStreamAt(0)); await reader1.LoadAsync((uint)originalData.Size); await reader2.LoadAsync((uint)protectedData.Size); EncryptDecryptText.Text += " Size of original stream: " + originalData.Size + "\n"; EncryptDecryptText.Text += " Size of protected stream: " + protectedData.Size + "\n"; if (originalData.Size == protectedData.Size) { buff1 = reader1.ReadBuffer((uint)originalData.Size); buff2 = reader2.ReadBuffer((uint)protectedData.Size); if (CryptographicBuffer.Compare(buff1, buff2)) { EncryptDecryptText.Text += "ProtectStreamAsync returned unprotected data"; return; } } EncryptDecryptText.Text += " Stream Compare completed. Streams did not match.\n"; source = protectedData.GetInputStreamAt(0); InMemoryRandomAccessStream unprotectedData = new InMemoryRandomAccessStream(); dest = unprotectedData.GetOutputStreamAt(0); // Unprotect DataProtectionProvider Provider2 = new DataProtectionProvider(); await Provider2.UnprotectStreamAsync(source, dest); if (await dest.FlushAsync()) { EncryptDecryptText.Text += " Unprotected output was successfully flushed\n"; } //Verify the unprotected data does match the original reader1 = new DataReader(originalData.GetInputStreamAt(0)); reader2 = new DataReader(unprotectedData.GetInputStreamAt(0)); await reader1.LoadAsync((uint)originalData.Size); await reader2.LoadAsync((uint)unprotectedData.Size); EncryptDecryptText.Text += " Size of original stream: " + originalData.Size + "\n"; EncryptDecryptText.Text += " Size of unprotected stream: " + unprotectedData.Size + "\n"; buff1 = reader1.ReadBuffer((uint)originalData.Size); buff2 = reader2.ReadBuffer((uint)unprotectedData.Size); if (!CryptographicBuffer.Compare(buff1, buff2)) { EncryptDecryptText.Text += "UnrotectStreamAsync did not return expected data"; return; } EncryptDecryptText.Text += "*** Done!\n"; }
/// <summary> /// This is the click handler for the 'RunSample' button. It is responsible for executing the sample code. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RunSample_Click(object sender, RoutedEventArgs e) { String algName = AlgorithmNames.SelectionBoxItem.ToString(); UInt32 KeySize = UInt32.Parse(KeySizes.SelectionBoxItem.ToString()); Scenario7Text.Text = ""; IBuffer Data; String cookie = "Some cookie to encrypt"; switch (AlgorithmNames.SelectedIndex) { case 0: Data = CryptographicBuffer.ConvertStringToBinary(cookie, BinaryStringEncoding.Utf16LE); break; // OAEP Padding depends on key size, message length and hash block length // // The maximum plaintext length is KeyLength - 2*HashBlock - 2 // // OEAP padding supports an optional label with the length is restricted by plaintext/key/hash sizes. // Here we just use a small label. case 1: Data = CryptographicBuffer.GenerateRandom(1024 / 8 - 2 * 20 - 2); break; case 2: Data = CryptographicBuffer.GenerateRandom(1024 / 8 - 2 * (256 / 8) - 2); break; case 3: Data = CryptographicBuffer.GenerateRandom(2048 / 8 - 2 * (384 / 8) - 2); break; case 4: Data = CryptographicBuffer.GenerateRandom(2048 / 8 - 2 * (512 / 8) - 2); break; default: Scenario7Text.Text += "An invalid algorithm was selected"; return; } IBuffer Encrypted; IBuffer Decrypted; IBuffer blobOfPublicKey; IBuffer blobOfKeyPair; // Crate an AsymmetricKeyAlgorithmProvider object for the algorithm specified on input. AsymmetricKeyAlgorithmProvider Algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algName); Scenario7Text.Text += "*** Sample Encryption Algorithm\n"; Scenario7Text.Text += " Algorithm Name: " + Algorithm.AlgorithmName + "\n"; Scenario7Text.Text += " Key Size: " + KeySize + "\n"; // Generate a random key. CryptographicKey keyPair = Algorithm.CreateKeyPair(KeySize); // Encrypt the data. try { Encrypted = CryptographicEngine.Encrypt(keyPair, Data, null); } catch (ArgumentException ex) { Scenario7Text.Text += ex.Message + "\n"; Scenario7Text.Text += "An invalid key size was selected for the given algorithm.\n"; return; } Scenario7Text.Text += " Plain text: " + Data.Length + " bytes\n"; Scenario7Text.Text += " Encrypted: " + Encrypted.Length + " bytes\n"; // Export the public key. blobOfPublicKey = keyPair.ExportPublicKey(); blobOfKeyPair = keyPair.Export(); // Import the public key. CryptographicKey keyPublic = Algorithm.ImportPublicKey(blobOfPublicKey); if (keyPublic.KeySize != keyPair.KeySize) { Scenario7Text.Text += "ImportPublicKey failed! The imported key's size did not match the original's!"; return; } // Import the key pair. keyPair = Algorithm.ImportKeyPair(blobOfKeyPair); // Check the key size of the imported key. if (keyPublic.KeySize != keyPair.KeySize) { Scenario7Text.Text += "ImportKeyPair failed! The imported key's size did not match the original's!"; return; } // Decrypt the data. Decrypted = CryptographicEngine.Decrypt(keyPair, Encrypted, null); if (!CryptographicBuffer.Compare(Decrypted, Data)) { Scenario7Text.Text += "Decrypted data does not match original!"; return; } }