title: Change Active Directory password using Kerberos Change-Password protocol and .NET Core 3
body: <p>It is possible to change password of AD user using LDAP protocol. However, if the user has to change his password at next logon (or the password is expired), then the password cannot be changed unless by using admin credentials. I was able to solve this issue <a href="https://stackoverflow.com/a/51511518/597657">in the past</a> by using WIN32 API. Unfortunately, I cannot use WINAPI in linux environment.</p>
  <p>As per <a href="https://support.microsoft.com/en-hk/help/264480/description-of-password-change-protocols-in-windows" rel="nofollow noreferrer">this article</a>:</p>
  <blockquote>
  <p>When a user changes his or her own password by pressing CTRL+ALT+DELETE and then clicking Change Password, Windows NT up to Windows 2003 the NetUserChangePassword mechanism (method 1) is used if the target is a domain. <strong>From Windows Vista onwards, the Kerberos change password protocol is used for domain accounts</strong>. If the target is a Kerberos realm, the Kerberos change-password protocol (method 3) is used.</p>
  </blockquote>
  <p>I looked for Kerberos client that can run on .NET Core and I found <a href="https://github.com/SteveSyfuhs/Kerberos.NET" rel="nofollow noreferrer"><code>SteveSyfuhs/Kerberos.NET</code></a>.</p>
  <p>By reading <a href="https://datatracker.ietf.org/doc/html/draft-ietf-cat-kerb-chg-password-02" rel="nofollow noreferrer">Kerberos Change Password Protocol</a> and <a href="https://github.com/SteveSyfuhs/Kerberos.NET/tree/master/Samples" rel="nofollow noreferrer">Kerberos.NET Samples</a>, I wrote the following code:</p>
  <pre><code>using Kerberos.NET;
  using Kerberos.NET.Client;
  using Kerberos.NET.Credentials;
  using Kerberos.NET.Crypto;
  using Kerberos.NET.Entities;
  using System;
  using System.Linq;
  using System.Net.Sockets;
  using System.Text;
  using System.Threading.Tasks;
  
  namespace KerberosDemo
  {
      class Program
      {
          static async Task Main(string[] args)
          {
              string activeDirectoryServer = &quot;10.12.34.56:88&quot;; // kdc port
              string domain = &quot;TEST.LOCAL&quot;;
              string username = &quot;testuser@&quot; + domain;
              string oldPassword = &quot;123&quot;;
              string newPassword = &quot;456&quot;;
  
              using var client = new KerberosClient(activeDirectoryServer);
              var kerbCred = new KerberosPasswordCredential(username, oldPassword, domain);
              await client.Authenticate(kerbCred);
              var serviceTicket = await client.GetServiceTicket(&quot;kadmin/changepw&quot;);
  
              var apReq = new KrbApReq
              {
                  Ticket = serviceTicket.Ticket,
                  Authenticator = KrbEncryptedData.Encrypt(Encoding.UTF8.GetBytes(newPassword).AsMemory(), kerbCred.CreateKey(), KeyUsage.ApReqAuthenticator),
                  ProtocolVersionNumber = 1
              };
  
              var tcp = client.Transports.FirstOrDefault(t =&gt; t.Protocol == ProtocolType.Tcp);
              await tcp.SendMessage&lt;KrbApReq, KrbAsRep&gt;(domain, apReq);
          }
      }
  }
  </code></pre>
  <p>I got the following exception at <code>await tcp.SendMessage&lt;KrbApReq, KrbAsRep&gt;(domain, apReq);</code>:</p>
  <blockquote>
  <p>Unhandled exception.
  System.Security.Cryptography.CryptographicException: ASN1 corrupted
  data.    at
  System.Security.Cryptography.Asn1.AsnReader.ReadTagAndLength(Nullable<code>1&amp; contentsLength, Int32&amp; bytesRead) in d:\a\1\s\Kerberos.NET\Asn1\Experimental\AsnReader.cs:line 305    at Kerberos.NET.Entities.KrbError.CanDecode(ReadOnlyMemory</code>1 encoded) in
  d:\a\1\s\Kerberos.NET\Entities\Krb\KrbError.cs:line 23    at
  Kerberos.NET.Transport.KerberosTransportBase.Decode[T](ReadOnlyMemory<code>1 response) in d:\a\1\s\Kerberos.NET\Client\Transport\KerberosTransportBase.cs:line 41    at Kerberos.NET.Transport.TcpKerberosTransport.ReadResponse[T](NetworkStream stream, CancellationToken cancellation) in d:\a\1\s\Kerberos.NET\Client\Transport\TcpKerberosTransport.cs:line 69 at Kerberos.NET.Transport.TcpKerberosTransport.SendMessage[T](String domain, ReadOnlyMemory</code>1 encoded, CancellationToken cancellation) in
  d:\a\1\s\Kerberos.NET\Client\Transport\TcpKerberosTransport.cs:line 58
  at KerberosDemo.Program.Main(String[] args)    at
  KerberosDemo.Program.(String[] args)</p>
  </blockquote>
  <p>Your help is appreciated. Thanks.</p>