<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pentagrid AG (Einträge über HMAC)</title><link>https://www.pentagrid.ch/</link><description></description><atom:link href="https://www.pentagrid.ch/de/categories/hmac.xml" rel="self" type="application/rss+xml"></atom:link><language>de</language><copyright>Contents © 2026 Pentagrid AG </copyright><lastBuildDate>Wed, 03 Jun 2026 09:19:03 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Parsing modern ASP.NET Core Identity password hashes to Hashcat</title><link>https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/</link><dc:creator>Yannic Hemmer, Pentagrid AG</dc:creator><description>&lt;p&gt;While this would not be anything out of the ordinary, the environment certainly was. So where do we expect ASP.NET Core Identity hashes? Some obscure cloud application, local Windows application, ... but surely not on an embedded linux system!?&lt;/p&gt;
&lt;p&gt;While the vulnerability itself was discovered at this point - exposing password hashes without any authentication is not exactly considered best practice - it was decided to investigate the password hashes further in an attempt to showcase password cracking and detect weak passwords.&lt;/p&gt;
&lt;p&gt;Despite numerous tools on the internet advertising the capability of converting ASP.NET Core Identity hashes into Hashcat format, all attempts at cracking the extracted password hashes remained unsuccessful despite knowing some pairs of plaintext passwords and ASP.NET Core Identity hashes.&lt;/p&gt;
&lt;p&gt;Why? It was time to dig in!&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;section id="no-country-for-old-hashes-cracking-asp-net-core-identity-with-hashcat"&gt;
&lt;h2&gt;No Country for Old Hashes: Cracking ASP.NET Core Identity with Hashcat&lt;/h2&gt;
&lt;p&gt;Before we look at why all of the current tools fail to correctly convert ASP.NET Core Identity hashes into Hashcat format, let us establish some background on the ASP.NET Core Identity Hashes.&lt;/p&gt;
&lt;section id="asp-net-core-identity-hashes"&gt;
&lt;h3&gt;ASP.NET Core Identity Hashes&lt;/h3&gt;
&lt;p&gt;Offical documentation from Microsoft on the structure is sparse. Luckily some amazing blog posts have been written by &lt;a class="reference external" href="https://www.strathweb.com/2023/03/beware-of-the-default-aspnet-identity-settings/"&gt;Filip W.&lt;/a&gt; and &lt;a class="reference external" href="https://www.blinkingcaret.com/2017/11/29/asp-net-identity-passwordhash/"&gt;Rui Figueiredo&lt;/a&gt;. To avoid regurgitating their entire works and opinions here, we are going to provide a brief overview of ASP.NET Core Identity password hashes:&lt;/p&gt;
&lt;p&gt;ASP.NET Core Identity hashes are base64-encoded byte structures split into multiple sets of magic length and values.&lt;/p&gt;
&lt;p&gt;The magic marker starts at the first byte, notated in the following as [0], called the format marker (mostly referred to as version) where we must differentiate between ASP.NET Core Identity v2 and v3 hashes.&lt;/p&gt;
&lt;p&gt;The old v2 hashes have a non-configurable structure: The format marker is followed by the salt [1,16] consisting of 16 bytes and the subkey [17,49] with 32 bytes. The key derivation PRF (pseudo-random function) is PBKDF2+HMAC-SHA1 with 1,000 iterations, taking the password and salt as input and producing the 32 bytes long subkey.&lt;/p&gt;
&lt;p&gt;With the introduction of ASP.NET Core Identity v3 hashes, the key derivation PRF, number of iterations, length of the salt, and length of the subkey can be customized. The PRF [1,4] can be chosen based on the &lt;code class="docutils literal"&gt;KeyDerivationPrf&lt;/code&gt; enum &lt;a class="brackets" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-1" id="footnote-reference-1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;: either HMACSHA1, HMACSHA256, or HMACSHA512.&lt;/p&gt;
&lt;p&gt;The number of iterations (ITER) [5,8] in combination with the chosen PRF defines the work factor.&lt;/p&gt;
&lt;p&gt;The length of the salt (SALTLEN) [9,12] is the input of a random number generator which generates the salt. The interval of the salt [13,(13+SALTLEN-1)] therefore depends on this length of the salt.&lt;/p&gt;
&lt;p&gt;After the salt, the actual subkey follows. The length of the subkey is not stored inside the ASP.NET Core Identity hash. Therefore, the only way to determine the length of the subkey is to read the byte structure until the end of the input [(13+SALTLEN-1), EOL]. Here, EOL represents the index of the last byte of the structure.&lt;/p&gt;
&lt;p&gt;Diving into the implementation in .NET, the &lt;code class="docutils literal"&gt;PasswordHasher&lt;/code&gt; class provides two methods of creating v3 hashes by overloading the HashPasswordV3 method &lt;a class="brackets" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-1" id="footnote-reference-2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;. The first method is a convenience wrapper of the second using static magic values. Here, PRF is set to HMAC-SHA512 (HMAC-SHA256 for .NET versions &amp;lt;7.0), ITER to 100,000 (10,000 for .NET versions &amp;lt;7.0), and SALTLEN to 16. Additionally, 32 bytes are requested back from the PRF (length of the subkey). These values are most often referenced as "default values".&lt;/p&gt;
&lt;p&gt;The non-wrapped method allows unrestricted configuration of these values. There is no apparent limit on ITER, SALTLEN, and number of requested subkey bytes. Only the PRF is constrained by the enum &lt;code class="docutils literal"&gt;Microsoft.AspNetCore.Cryptography.KeyDerivation&lt;/code&gt; &lt;a class="brackets" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-2" id="footnote-reference-3" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;4&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While we did not encounter any example that deviates from these "default values", simply assuming static magic values when reading a v3 hash will result in incorrect handling for the "non-default" ASP.NET Core Identity v3 hashes.&lt;/p&gt;
&lt;p&gt;The following Listing shows the above described structure of ASP.NET Core Identity hashes:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-1" name="rest_code_1173a2a53af64d4ab9561154f33600b1-1" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-1"&gt;&lt;/a&gt;| [0] | ...
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-2" name="rest_code_1173a2a53af64d4ab9561154f33600b1-2" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-2"&gt;&lt;/a&gt;   |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-3" name="rest_code_1173a2a53af64d4ab9561154f33600b1-3" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-3"&gt;&lt;/a&gt;   '--&amp;gt; 0x00 ASP.NET Core Identity hashing logic version v2
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-4" name="rest_code_1173a2a53af64d4ab9561154f33600b1-4" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-4"&gt;&lt;/a&gt;   |    | [0]  | [1,16] | [17,49] |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-5" name="rest_code_1173a2a53af64d4ab9561154f33600b1-5" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-5"&gt;&lt;/a&gt;   |    | 0x00 | SALT   | SUBKEY  |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-6" name="rest_code_1173a2a53af64d4ab9561154f33600b1-6" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-6"&gt;&lt;/a&gt;   |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-7" name="rest_code_1173a2a53af64d4ab9561154f33600b1-7" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-7"&gt;&lt;/a&gt;   '--&amp;gt; 0x01 ASP.NET Core Identity hashing logic version v3
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-8" name="rest_code_1173a2a53af64d4ab9561154f33600b1-8" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-8"&gt;&lt;/a&gt;        | [0]  | [1,4] | [5,8] | [9,12]  | [13,(13+SALTLEN-1)] | [(13+SALTLEN),EOL] |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-9" name="rest_code_1173a2a53af64d4ab9561154f33600b1-9" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-9"&gt;&lt;/a&gt;        | 0x01 | PRF   | ITER  | SALTLEN | SALT                | SUBKEY             |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-10" name="rest_code_1173a2a53af64d4ab9561154f33600b1-10" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-10"&gt;&lt;/a&gt;                   |       |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-11" name="rest_code_1173a2a53af64d4ab9561154f33600b1-11" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-11"&gt;&lt;/a&gt;                   |       ' --&amp;gt;  10,000 (HMAC-SHA256 .NET &amp;lt; 7.0 default)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-12" name="rest_code_1173a2a53af64d4ab9561154f33600b1-12" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-12"&gt;&lt;/a&gt;                   |       ' --&amp;gt; 100,000 (HMAC-SHA512 .NET &amp;gt;= 7.0 default)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-13" name="rest_code_1173a2a53af64d4ab9561154f33600b1-13" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-13"&gt;&lt;/a&gt;                   |
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-14" name="rest_code_1173a2a53af64d4ab9561154f33600b1-14" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-14"&gt;&lt;/a&gt;                   ' --&amp;gt; 0x00 HMAC-SHA1
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-15" name="rest_code_1173a2a53af64d4ab9561154f33600b1-15" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-15"&gt;&lt;/a&gt;                   ' --&amp;gt; 0x01 HMAC-SHA256
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-16" name="rest_code_1173a2a53af64d4ab9561154f33600b1-16" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-16"&gt;&lt;/a&gt;                   ' --&amp;gt; 0x02 HMAC-SHA512
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-17" name="rest_code_1173a2a53af64d4ab9561154f33600b1-17" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-17"&gt;&lt;/a&gt;   ASP.NET_IDENTITY_HASH_...
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-18" name="rest_code_1173a2a53af64d4ab9561154f33600b1-18" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-18"&gt;&lt;/a&gt;       SALT (32 bytes)    --&amp;gt; Password salt used in PBKDF2+HMAC-SHA{1,256,512} function
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-19" name="rest_code_1173a2a53af64d4ab9561154f33600b1-19" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-19"&gt;&lt;/a&gt;       SUBKEY (32 bytes)  --&amp;gt; Result of PBKDF2+HMAC-SHA{1,256,512}
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-20" name="rest_code_1173a2a53af64d4ab9561154f33600b1-20" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-20"&gt;&lt;/a&gt;
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-21" name="rest_code_1173a2a53af64d4ab9561154f33600b1-21" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-21"&gt;&lt;/a&gt;       (only v2 -- method HashPasswordV2 in [#1]_)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-22" name="rest_code_1173a2a53af64d4ab9561154f33600b1-22" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-22"&gt;&lt;/a&gt;       Number of iterations: 1,000 (static)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-23" name="rest_code_1173a2a53af64d4ab9561154f33600b1-23" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-23"&gt;&lt;/a&gt;       Length of the salt: 16 bytes (static)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-24" name="rest_code_1173a2a53af64d4ab9561154f33600b1-24" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-24"&gt;&lt;/a&gt;       Length of the subkey: 32 bytes (static)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-25" name="rest_code_1173a2a53af64d4ab9561154f33600b1-25" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-25"&gt;&lt;/a&gt;
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-26" name="rest_code_1173a2a53af64d4ab9561154f33600b1-26" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-26"&gt;&lt;/a&gt;       (only v3 -- method HashPasswordV3 in [#1]_)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-27" name="rest_code_1173a2a53af64d4ab9561154f33600b1-27" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-27"&gt;&lt;/a&gt;       PRF  (uint32BE)    --&amp;gt; Pseudo-random function used for key derivation (see [#2]_)
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-28" name="rest_code_1173a2a53af64d4ab9561154f33600b1-28" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-28"&gt;&lt;/a&gt;       ITER (uint32BE)    --&amp;gt; Number of iterations the hashing algorithm is applied
&lt;a id="rest_code_1173a2a53af64d4ab9561154f33600b1-29" name="rest_code_1173a2a53af64d4ab9561154f33600b1-29" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_1173a2a53af64d4ab9561154f33600b1-29"&gt;&lt;/a&gt;       SALTLEN (uint32BE) --&amp;gt; Length of the salt (saltSize)
&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id="asp-net-core-idenity-hash-to-hashcat-format-convertion"&gt;
&lt;h3&gt;ASP.NET Core Idenity Hash to Hashcat Format Convertion&lt;/h3&gt;
&lt;p&gt;To generate valid Hashcat format from ASP.NET Core Identity hashes, the PRF, number of iterations, salt, and subkey must be brought into the following structure:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_4b80e68f2a274d23bff79951345d960b-1" name="rest_code_4b80e68f2a274d23bff79951345d960b-1" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_4b80e68f2a274d23bff79951345d960b-1"&gt;&lt;/a&gt;&amp;lt;PRF&amp;gt;:&amp;lt;ITER&amp;gt;:&amp;lt;base64enc(SALT)&amp;gt;:&amp;lt;base64enc(SUBKEY)&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let us do this process for the following ASP.NET Core Identity password hash:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_6694ce227da549db832e2afc74d3cc28-1" name="rest_code_6694ce227da549db832e2afc74d3cc28-1" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_6694ce227da549db832e2afc74d3cc28-1"&gt;&lt;/a&gt;AQAAAAIAAYagAAAAEPcrvDihsovZNHxRFrv1y3i4qfjKsXn+JzKD7AOIlxe5YSb/s+tMXJVQeU1//VQXow==
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Base64-decoded and structured:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-1" name="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-1" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-1"&gt;&lt;/a&gt;01 := (0x) ASP.NET Core Identity v3 hash
&lt;a id="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-2" name="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-2" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-2"&gt;&lt;/a&gt;00000002 := (0x) HMAC-SHA512
&lt;a id="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-3" name="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-3" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-3"&gt;&lt;/a&gt;000186a0 := (0x) 0d100,000 iterations
&lt;a id="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-4" name="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-4" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-4"&gt;&lt;/a&gt;f7 2b bc 38 a1 b2 8b d9 34 7c 51 16 bb f5 cb 78 := salt
&lt;a id="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-5" name="rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-5" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_d3d9ee47dd1b469f925631c3e31b5d5b-5"&gt;&lt;/a&gt;b8 a9 f8 ca b1 79 fe 27 32 83 ec 03 88 97 17 b9 61 26 ff b3 eb 4c 5c 95 50 79 4d 7f fd 54 17 a3 := subkey
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ASP.NET Core Identity v3 hash PRF, iterations, salt, and subkey converted to Hashcat format:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code text"&gt;&lt;a id="rest_code_fcc97ae859ae4735896905b7c5b733ed-1" name="rest_code_fcc97ae859ae4735896905b7c5b733ed-1" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#rest_code_fcc97ae859ae4735896905b7c5b733ed-1"&gt;&lt;/a&gt;sha512:100000:9yu8OKGyi9k0fFEWu/XLeA==:uKn4yrF5/icyg+wDiJcXuWEm/7PrTFyVUHlNf/1UF6M=
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When attempting to break the ASP.NET Core Identity hashes with Hashcat, we need to ensure that Hashcat correctly identifies the hash type or set it manually with the &lt;a class="reference external" href="https://hashcat.net/wiki/doku.php?id=example_hashes"&gt;hash-mode&lt;/a&gt; (aka &lt;a class="reference external" href="https://hashcat.net/wiki/doku.php?id=hashcat"&gt;hash-type&lt;/a&gt;). This also means that we need to use multiple Hashcat runs when encountering differing PRFs. Ideally, the hashes with differing PRFs are split into multiple files.&lt;/p&gt;
&lt;table class="align-center" style="width: 55%;"&gt;
&lt;caption&gt;Table showing the different hash types per ASP.NET version/format marker and .NET versions, as well as the corresponding Hashcat hash-mode (&lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;-m&lt;/span&gt;&lt;/code&gt; parameter).&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th class="head"&gt;&lt;p&gt;ASP.NET version&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Hash type&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Hashcat hash-mode&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;v2, v3&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA1&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;12000&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;v3&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA256&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;10900&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;v3 (.NET &amp;gt; 7.0)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA512&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;12100&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id="current-tooling"&gt;
&lt;h3&gt;Current Tooling&lt;/h3&gt;
&lt;p&gt;From what we have seen so far, the process of converting ASP.NET Core Identity hashes seems a bit convoluted due to their magic structure, but otherwise relatively straightforward.&lt;/p&gt;
&lt;p&gt;So what occurred during initial attempts of converting the hash with one of the available tools? The tried tools being:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/edernucci/identity-to-hashcat.git"&gt;identity-to-hashcat&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/brunobritodev/Hashcat.ASPNET.Identity.git"&gt;ASP.NET Identity - Hashcat&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://github.com/Yeeb1/ASP.NETIdentity2hashcat.git"&gt;ASP.NETIdentity2hashcat&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;ASP.NETIdentity2hashcat&lt;/em&gt; and &lt;em&gt;identity-to-hashcat&lt;/em&gt; both lack the support for ASP.NET Core Identity v3 hashes from .NET versions 7.0 or higher. Instead, they wrongfully default to a statically set SHA256 as the PRF.&lt;/p&gt;
&lt;p&gt;Further, &lt;em&gt;ASP.NETIdentity2hashcat&lt;/em&gt; uses the wrong byte interval for the number of iterations, returning the encoded PRF enum instead.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ASP.NET Identity&lt;/em&gt; seems to use a more solid approach by using the &lt;code class="docutils literal"&gt;AspNetIdentityHashInfo&lt;/code&gt; class from the &lt;code class="docutils literal"&gt;NetDevPack.Utilities&lt;/code&gt; namespace instead of using their own implementation. Yet similarly, this falls short of .NET version 7.0 and higher compatibility. In this case it was necessary to dig deeper to find out why the resulting Hashcat hashes cannot be broken. The answer lies in the &lt;a class="reference external" href="https://github.com/NetDevPack/NetDevPack/blob/b3106b87ff617dd00b644ab385e3165a09ee518f/src/NetDevPack/Utilities/AspNetIdentityHashInfo.cs"&gt;NetDevPack&lt;/a&gt; repo on commit b3106b8. Therefore, all three tools do not handle configured ASP.NET Core Identity v3 hashes: Only SHA256 support as well as the &lt;em&gt;default values&lt;/em&gt; for the length of the salt and length of subkey are statically assumed as 16 and 32 bytes respectively.&lt;/p&gt;
&lt;p&gt;Instead of displaying any warnings or errors, the tools report back false PRFs, salts, and subkeys.&lt;/p&gt;
&lt;p&gt;TL;DR. The tested tools lack support for the PRF HMAC-SHA512 which was introduced with .NET version 7.0 (which was released in 2022). We need a tool that supports all currently supported ASP.NET Core Identity hashes and .NET versions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="contributions"&gt;
&lt;h3&gt;Contributions&lt;/h3&gt;
&lt;p&gt;Instead of extending one of the existing tools, a ground-up approach was taken to reach the following goals:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear type system&lt;/strong&gt; for the structured components of ASP.NET Core Identity hashes. Errors are thrown if parsed content does not fit type system. Type system can be extended for future .NET releases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;dl class="simple"&gt;
&lt;dt&gt;&lt;strong&gt;Input of ASP.NET Core Identity hashes:&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Capability to parse large numbers of ASP.NET Core Identity hashes at once. This allows us to parse entire excerpts of real-world ASP.NET Core Identity databases which may hold hundreds of user entries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allow annotations of the hashes which can be used for usernames, suspected passwords, or other remarks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="simple"&gt;
&lt;dt&gt;&lt;strong&gt;Output of Hashcat formatted hashes:&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Structured output split by PRF due to Hashcat expecting only a single hash type in its input file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Annotations from input file can be prepended to the formatted hashes for compatibility with the Hashcat &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;--username&lt;/span&gt;&lt;/code&gt; option.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation on the ASP.NET Core Identity&lt;/strong&gt; structure, conversion process, and supported versions/PRFs. At time of writing v2 and v3 (PBKDF2+HMAC-SHA{1,256,512}) with default or custom configuration hashes are supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test cases for all "default variants"&lt;/strong&gt; of ASP.NET Core Identity hashes to confirm proper conversion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verbose output options&lt;/strong&gt; to allow debugging.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The conversion script is hosted at &lt;a class="reference external" href="https://codeberg.org/pentagridsec/convertASPdotNETIdentityHash2hashcatFormat"&gt;Codeberg&lt;/a&gt; and at &lt;a class="reference external" href="https://github.com/pentagridsec/convertASPdotNETIdentityHash2hashcatFormat"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="recommendation-for-asp-net-core-identity-production-use"&gt;
&lt;h3&gt;Recommendation for ASP.NET Core Identity Production Use&lt;/h3&gt;
&lt;p&gt;If you are using ASP.NET Core Identity hashes for authentication, we strongly recommend reviewing the work effort of all stored hashes. OWASP publishes and continuously updates their recommendations for the &lt;a class="reference external" href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2"&gt;work effort of PBKDF2&lt;/a&gt;. The .NET "defaults" do not meet these recommendations at all:&lt;/p&gt;
&lt;table class="align-center" style="width: 55%;"&gt;
&lt;caption&gt;Table showing the number of iterations over different key derivation/hashing algorithms used as .NET "defaults", which represents the work effort, compared to the OWASP recommendations as of 2026-06-01.&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th class="head"&gt;&lt;p&gt;Key derivation and hash&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;.NET "defaults"&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;OWASP recommendations&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA1&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;1,000&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;1,400,000 iterations&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA256&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;10,000&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;600,000 iterations&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;PBKDF2+HMAC-SHA512&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;100,000&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;220,000 iterations&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;To the best of our knowledge, newly created "default" ASP.NET Core Identity v3 hashes for &lt;a class="reference external" href="https://github.com/dotnet/AspNetCore/blob/main/src/Identity/Extensions.Core/src/PasswordHasher.cs"&gt;.NET version 7.0+&lt;/a&gt; use PBKDF2-HMAC-SHA512 which only lags behind the OWASP recommendations by a factor of two.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/aspnet/Identity/blob/master/src/Core/PasswordHasher.cs"&gt;.NET versions below 7.0&lt;/a&gt; ASP.NET Core Identity v3 "default" hashes use PBKDF2-HMAC-SHA256 with work effort an order of magnitude lower than recommended by OWASP.&lt;/p&gt;
&lt;p&gt;Regardless of the .NET version: If ASP.NET Core Identity v2 hashes are generated, PBKDF2-HMAC-SHA1 with 1,000 iterations will always be used. This is multiple magnitudes below current OWASP recommendations. It cannot be customized. This poses direct risk by allowing attackers to break hashed and salted passwords without major computational and time effort. Therefore, v2 hashes are always a bad sign.&lt;/p&gt;
&lt;p&gt;Perhaps it would be a good time for Microsoft to set their own standards or mandate those of others, rather than &lt;a class="reference external" href="https://learn.microsoft.com/en-us/security/engineering/cryptographic-recommendations#key-derivation-functions"&gt;passing the buck down&lt;/a&gt; to developers and customers.&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="footnote-1" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;3&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="backrefs"&gt;(&lt;a role="doc-backlink" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-reference-1"&gt;1&lt;/a&gt;,&lt;a role="doc-backlink" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-reference-2"&gt;2&lt;/a&gt;)&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/dotnet/aspnetcore/blob/c0c2230799a3f876aa673a66bc008bf9b803acac/src/Identity/Extensions.Core/src/PasswordHasher.cs"&gt;Source file PasswordHasher.cs in ASP.NET Core&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="footnote-2" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/#footnote-reference-3"&gt;4&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;a class="reference external" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivationprf?view=aspnetcore-10.0"&gt;API ASP.NET Core KeyDerivationPrf Enum&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;</description><guid>https://www.pentagrid.ch/de/blog/parsing-modern-aspnet-core-identity-password-hashes-to-hashcat/</guid><pubDate>Wed, 03 Jun 2026 09:23:00 GMT</pubDate></item></channel></rss>