{"id":109580,"date":"2024-03-27T07:00:00","date_gmt":"2024-03-27T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109580"},"modified":"2024-03-27T07:14:13","modified_gmt":"2024-03-27T14:14:13","slug":"20240327-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240327-00\/?p=109580","title":{"rendered":"Some choices for encrypting data so that it can be decrypted only by the same user or computer"},"content":{"rendered":"<p>One of the functions that Windows makes available to you for encrypting data is <code>Crypt\u00adProtect\u00adData<\/code>. (<a title=\"When I call CryptProtectData with the same parameters, why arent the results identical?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181008-00\/?p=99915\">Previously<\/a>.) This function gives you some options for who can decrypt the data:<\/p>\n<ul>\n<li>The same user on the same machine.<\/li>\n<li>Any user on the same machine.<\/li>\n<\/ul>\n<p>The resulting binary blob can be saved anywhere, and can later be loaded back into memory by any process running within the same scope\u00b9 and passed to <code>Crypt\u00adUnprotect\u00adData<\/code> to recover the original data.<\/p>\n<p>(Here&#8217;s some <a href=\"https:\/\/docs.microsoft.com\/windows\/win32\/seccrypto\/example-c-program-using-cryptprotectdata\"> sample code<\/a>.)<\/p>\n<p>Alternatively, you can use <code>Windows.<wbr \/>Security.<wbr \/>Cryptography.<wbr \/>Data\u00adProtection.<wbr \/>Data\u00adProtection\u00adProvider<\/code>. When encrypting, you construct the <code>Data\u00adProtection\u00adProvider<\/code> with a string that describes who can decrypt the data.<\/p>\n<ul>\n<li>C++\/WinRT: <code>auto protector = DataProtectionProvider(scope);<\/code><\/li>\n<li>C++\/WinRT: <code>DataProtectionProvider protector{ scope };<\/code><\/li>\n<li>C++\/CX: <code>auto protector = ref new DataProtectionProvider(scope);<\/code><\/li>\n<li>C#: <code>var protector = new DataProtectionProvider(scope);<\/code><\/li>\n<li>JavaScript: <code>var protector = new DataProtectionProvider(scope);<\/code><\/li>\n<\/ul>\n<p>The <code>Data\u00adProtection\u00adProvider<\/code> gives you a wider choice of scopes than <code>Crypt\u00adProtect\u00adData<\/code>.<\/p>\n<ul>\n<li>Current user.<\/li>\n<li>Current machine.<\/li>\n<li>Specific Active Directory user or group. (Requires enterpriseData capability.)<\/li>\n<li>Specific Web site password.<\/li>\n<\/ul>\n<p>Once you&#8217;ve created a <code>Data\u00adProtection\u00adProvider<\/code>, you can use the <code>Protect\u00adAsync<\/code> and <code>Protect\u00adStream\u00adAsync<\/code> methods to encrypt a binary blob or data stream (respectively). In both cases, the resulting binary blob or stream can be saved anywhere.<\/p>\n<p>To decrypt, create a <code>Data\u00adProtection\u00adProvider<\/code> using the default (0-parameter) constructor, and then call <code>Unprotect\u00adAsync<\/code> or <code>Unprotect\u00adStream\u00adAsync<\/code> to recover the original data.<\/p>\n<p>(Here&#8217;s some <a href=\"https:\/\/learn.microsoft.com\/uwp\/api\/Windows.Security.Cryptography.DataProtection.DataProtectionProvider\"> sample code<\/a>.)<\/p>\n<p>Really, the <code>Data\u00adProtection\u00adProvider<\/code> is two different features glued together. First is encryption, which requires a scope. Second is decryption, which rejects a scope. Clearer would have to been to keep the separate functionality in separate objects.<\/p>\n<pre>runtimeclass DataProtectionEncryptionProvider\r\n{\r\n    DataProtectionEncryptionProvider(String scope);\r\n\r\n    IAsyncOperation&lt;IBuffer&gt; ProtectAsync(IBuffer data);\r\n    IAsyncAction ProtectStreamAsync(IInputStream src, IOutputStream dest);\r\n}\r\n\r\nruntimeclass DataProtectionDecryptionProvider\r\n{\r\n    DataProtectionDecryptionProvider();\r\n\r\n    IAsyncOperation&lt;IBuffer&gt; UnprotectAsync(IBuffer data);\r\n    IAsyncAction UnprotectStreamAsync(IInputStream src, IOutputStream dest);\r\n}\r\n<\/pre>\n<p>With this alternate design, you can&#8217;t accidentally try to encrypt with an unscoped provider, and it removes the confusion over whether the scope you use for decryption needs to match the one that was used for encryption.<\/p>\n<p>But really, the decryption provider is stateless, so the decryption methods can just be static, and that also avoids the confusion.<\/p>\n<pre>runtimeclass DataProtectionProvider\r\n{\r\n    DataProtectionProvider(String scope);\r\n\r\n    IAsyncOperation&lt;IBuffer&gt; ProtectAsync(IBuffer data);\r\n    IAsyncAction ProtectStreamAsync(IInputStream src, IOutputStream dest);\r\n\r\n    static IAsyncOperation&lt;IBuffer&gt; UnprotectAsync(IBuffer data);\r\n    static UnprotectStreamAsync(IInputStream src, IOutputStream dest);\r\n}\r\n<\/pre>\n<p><b>Bonus chatter<\/b>: The <code>Data\u00adProtection\u00adProvider<\/code> is just a wrapper around the <code>NCrypt\u00adProtect\u00adSecret<\/code> and <code>NCrypt\u00adUnprotect\u00adSecret<\/code> functions (for buffers) and te <code>NCrypt\u00adStream\u00adOpen\u00adTo\u00adProtect<\/code> and <code>NCrypt\u00adStream\u00adOpen\u00adTo\u00adUnprotect<\/code> functions (for streams).<\/p>\n<p><b>Bonus bonus chatter<\/b>: <code>Crypt\u00adProtect\u00adData<\/code> and <code>Data\u00adProtection\u00adProvider<\/code> are not interoperable. Data encrypted by one cannot be decrypted by the other.<\/p>\n<p>\u00b9 Sometimes people ask whether the memory must be decrypted from the same buffer returned by <code>Crypt\u00adProtect\u00adData<\/code>. No, it doesn&#8217;t. You can save the bytes to a file or copy them to another buffer. Just pass those same bytes back when you&#8217;re ready to decrypt. (After all, if the memory must be decrypted from literally the same buffer, that would prevent cross-process decryption and render moot all of the discussion in the documentation about roaming users, since roaming users are decrypting from another computer entirely.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There&#8217;s your classic, and there&#8217;s some newfangled stuff.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-109580","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There&#8217;s your classic, and there&#8217;s some newfangled stuff.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109580","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109580"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109580\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109580"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109580"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109580"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}