{"componentChunkName":"component---src-templates-blog-post-js","path":"/20201207-security--hashing-pwd-cs","result":{"data":{"site":{"siteMetadata":{"title":"dfaiv-dev","siteUrl":"https://blog.dfaiv.dev"}},"markdownRemark":{"id":"0ce2fda4-2096-517a-969f-ff968303e983","excerpt":"I wanted to add authorization to a SPA web api backend (using asp.net core). The build in solutions seem to either be IdentityServer4 (which will only be…","html":"<p>I wanted to add authorization to a SPA web api backend (using asp.net core). The build in solutions seem to either be <strong><a href=\"https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">IdentityServer4</a></strong> <del>(which <a href=\"https://identityserver4.readthedocs.io/en/latest/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">will only be supported unitl Nov 2022?</a>)</del> (wait, <a href=\"https://blog.duendesoftware.com/posts/20201210_community_edition/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">maybe they’ll have a Community Edition</a> for companies with less that $1M revenue?) or <strong><a href=\"https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&#x26;tabs=visual-studio\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Microsoft.AspNetCore.Identity</a></strong> which seems to want to work more with MVC/Razor and SPAs (though I’m sure it could be hacked?).</p>\n<p>Seems like it shouldn’t be the end of the world to create a user table and store passwords with some sort of best practice. The first part of that would be how to hash the password. Unsurprisingly there seem to be a few opinions around the inter-webs. This is what I ended up with.</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre class=\"language-csharp\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Pbkdf2PasswordHasher</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token class-name\"><span class=\"token keyword\">int</span></span> PasswordHashSize <span class=\"token operator\">=</span> <span class=\"token number\">512</span> <span class=\"token operator\">/</span> <span class=\"token number\">8</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token class-name\"><span class=\"token keyword\">int</span></span> SaltSize <span class=\"token operator\">=</span> <span class=\"token number\">256</span> <span class=\"token operator\">/</span> <span class=\"token number\">8</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">static</span> <span class=\"token keyword\">readonly</span> <span class=\"token class-name\">HashAlgorithmName</span> HashAlgorithm <span class=\"token operator\">=</span> \n        HashAlgorithmName<span class=\"token punctuation\">.</span>SHA512<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">string</span></span> <span class=\"token function\">Generate</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">string</span></span> password<span class=\"token punctuation\">,</span> \n        <span class=\"token class-name\"><span class=\"token keyword\">int</span></span> iterations <span class=\"token operator\">=</span> <span class=\"token number\">175_000</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">//generate a random salt for hashing</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> salt <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\"><span class=\"token keyword\">byte</span></span><span class=\"token punctuation\">[</span>SaltSize<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">RNGCryptoServiceProvider</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">GetBytes</span><span class=\"token punctuation\">(</span>salt<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">//hash password given salt and iterations</span>\n        <span class=\"token comment\">//iterations provide difficulty when cracking</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> pbkdf2 <span class=\"token operator\">=</span> \n            <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">Rfc2898DeriveBytes</span><span class=\"token punctuation\">(</span>\n                password<span class=\"token punctuation\">,</span> salt<span class=\"token punctuation\">,</span> iterations<span class=\"token punctuation\">,</span> HashAlgorithm<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> hash <span class=\"token operator\">=</span> pbkdf2<span class=\"token punctuation\">.</span><span class=\"token function\">GetBytes</span><span class=\"token punctuation\">(</span>PasswordHashSize<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">//return delimited string with salt | #iterations | hash</span>\n        <span class=\"token keyword\">return</span> Convert<span class=\"token punctuation\">.</span><span class=\"token function\">ToBase64String</span><span class=\"token punctuation\">(</span>salt<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"|\"</span> \n                <span class=\"token operator\">+</span> iterations <span class=\"token operator\">+</span> <span class=\"token string\">\"|\"</span> \n                <span class=\"token operator\">+</span> Convert<span class=\"token punctuation\">.</span><span class=\"token function\">ToBase64String</span><span class=\"token punctuation\">(</span>hash<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">bool</span></span> <span class=\"token function\">IsValid</span><span class=\"token punctuation\">(</span><span class=\"token class-name\"><span class=\"token keyword\">string</span></span> password<span class=\"token punctuation\">,</span> <span class=\"token class-name\"><span class=\"token keyword\">string</span></span> encodedHash<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">//extract original values from delimited hash text</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> parts <span class=\"token operator\">=</span> encodedHash<span class=\"token punctuation\">.</span><span class=\"token function\">Split</span><span class=\"token punctuation\">(</span><span class=\"token string character\">'|'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> salt <span class=\"token operator\">=</span> Convert<span class=\"token punctuation\">.</span><span class=\"token function\">FromBase64String</span><span class=\"token punctuation\">(</span>parts<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> iterations <span class=\"token operator\">=</span> <span class=\"token keyword\">int</span><span class=\"token punctuation\">.</span><span class=\"token function\">Parse</span><span class=\"token punctuation\">(</span>parts<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> hash <span class=\"token operator\">=</span> parts<span class=\"token punctuation\">[</span><span class=\"token number\">2</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">//generate hash from test password </span>\n        <span class=\"token comment\">//  and original salt and iterations</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> pbkdf2 <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">Rfc2898DeriveBytes</span><span class=\"token punctuation\">(</span>\n                        password<span class=\"token punctuation\">,</span> salt<span class=\"token punctuation\">,</span> iterations<span class=\"token punctuation\">,</span> HashAlgorithm<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> testHash <span class=\"token operator\">=</span> pbkdf2<span class=\"token punctuation\">.</span><span class=\"token function\">GetBytes</span><span class=\"token punctuation\">(</span>PasswordHashSize<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">//if hash values match then return success</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Convert<span class=\"token punctuation\">.</span><span class=\"token function\">ToBase64String</span><span class=\"token punctuation\">(</span>testHash<span class=\"token punctuation\">)</span> <span class=\"token operator\">==</span> hash<span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">//no match return false</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Notes</h3>\n<ul>\n<li>\n<p><code class=\"language-text\">interationCount</code> was used by running a perf test on my local machine to find hashing that took ~100ms</p>\n<div class=\"gatsby-highlight\" data-language=\"cs\"><pre class=\"language-cs\"><code class=\"language-cs\"><span class=\"token punctuation\">[</span><span class=\"token attribute\"><span class=\"token class-name\">Fact</span><span class=\"token attribute-arguments\"><span class=\"token punctuation\">(</span>Skip <span class=\"token operator\">=</span> <span class=\"token string\">\"not really a unit test, should probably move to some other mechanism.\"</span><span class=\"token punctuation\">)</span></span></span><span class=\"token punctuation\">]</span>\n<span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">void</span></span> <span class=\"token function\">Perf</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n<span class=\"token keyword\">const</span> <span class=\"token class-name\"><span class=\"token keyword\">int</span></span> maxRuntimeMs <span class=\"token operator\">=</span> <span class=\"token number\">200</span><span class=\"token punctuation\">;</span>\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> iterations <span class=\"token operator\">=</span> <span class=\"token number\">10_000</span><span class=\"token punctuation\">;</span>\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> lastRuntime <span class=\"token operator\">=</span> <span class=\"token number\">0L</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">while</span> <span class=\"token punctuation\">(</span>lastRuntime <span class=\"token operator\">&lt;</span> maxRuntimeMs<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> timer <span class=\"token operator\">=</span> Stopwatch<span class=\"token punctuation\">.</span><span class=\"token function\">StartNew</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> hashResult <span class=\"token operator\">=</span>\n        Pbkdf2PasswordHasher<span class=\"token punctuation\">.</span><span class=\"token function\">Generate</span><span class=\"token punctuation\">(</span>\n            PasswordPlainTextDefault<span class=\"token punctuation\">,</span>\n            iterations<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    timer<span class=\"token punctuation\">.</span><span class=\"token function\">Stop</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> runTime <span class=\"token operator\">=</span> timer<span class=\"token punctuation\">.</span>ElapsedMilliseconds<span class=\"token punctuation\">;</span>\n    _testOutputHelper<span class=\"token punctuation\">.</span><span class=\"token function\">WriteLine</span><span class=\"token punctuation\">(</span><span class=\"token interpolation-string\"><span class=\"token string\">$\"hash with iterations: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token expression language-csharp\">iterations</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">, ms: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token expression language-csharp\">runTime</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">, result: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token expression language-csharp\">hashResult</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    lastRuntime <span class=\"token operator\">=</span> runTime<span class=\"token punctuation\">;</span>\n    iterations <span class=\"token operator\">+=</span> <span class=\"token number\">5000</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n</li>\n<li>I used <code class=\"language-text\">HashAlgorithmName.SHA512</code> instead of <code class=\"language-text\">SHA256</code> because larger is better?</li>\n</ul>\n<h3>bcrypt</h3>\n<p>There is a <code class=\"language-text\">dotnet</code> <code class=\"language-text\">bcrypt</code> implementation which seems to more widely respected on the internet (as it is slower to calculate, and slower is better?). But <code class=\"language-text\">PBKDF2</code> still seems to be “officially” recommended, and it’s built into <code class=\"language-text\">dotnet</code> which seemed a little safer than OSS.</p>\n<h3>Resources:</h3>\n<ul>\n<li><a href=\"https://www.cidean.com/blog/2019/password-hashing-using-rfc2898derivebytes/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">C# pdfh source</a></li>\n<li><a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">PBKDF2 Recommendation by NIST</a></li>\n<li><a href=\"https://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pkbdf2-sha256\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">PBKDF2 Iterations Recommendation</a></li>\n<li><a href=\"https://github.com/aspnet/Identity/blob/master/src/Core/PasswordHasher.cs\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Microsoft.AspNetCore.Identity.PasswordHasher</a></li>\n</ul>","frontmatter":{"title":"How Should I Be Hashing Passwords in C#/dotnet core?","date":"December 07, 2020","description":"","slug":"/20201207-security--hashing-pwd-cs"}},"previous":{"frontmatter":{"title":"Angular - Can You Use an Async Variable in a Pipe?","slug":"/20201120-ng-async-var-in-a-pipe"}},"next":null},"pageContext":{"id":"0ce2fda4-2096-517a-969f-ff968303e983","previousPostId":"b6aa9cb7-7afa-53a8-b6af-f59897fec00a","nextPostId":null}},"staticQueryHashes":["2841359383","3825813668"]}