13 Replies Latest reply on Mar 18, 2011 11:19 PM by 772115

    Decrypting encPart  example?  Checksum failed

      I'm trying to decrypt the encrypted data part of the Kerberos ticket. My understanding of the algorithm is where I believe I'm mixed up somewhere (all code is server side):

      1) The login context on the server side provides a Subject which contains the private key of the server when storeKey=true in the configuration, of type KerberosKey. This is the key that can be used to decrypt the EncryptedPart of the client's ticket.
      LoginContext lc = new LoginContext(LCONF_SVR, new TextCallbackHandler());
      Subject sub = lc.getSubject();
      // Get KerberosKey from private creds
      for (Iterator i = sub.getPrivateCredentials().iterator(); i.hasNext();) {
          Object o = i.next();
          if (o instanceof KerberosKey) {
              svrPrivKey = (KerberosKey)o;
      2) This KerberosKey can be used to create an EncryptionKey:
      EncryptionKey privKey = new EncryptionKey(svrPrivKey.getEncoded(),
      2) When con.requestCredDeleg(true) on the client side, after con.isEstablished()==true, con.getDelegCred() on the server side returns a GSSCredentials which, along with con.getSrcName(), can create a Subject the contains the client's KerberosTicket in it's private credentials.
      Subject delegSub = GSSUtil.getSubject(con.getSrcName(), con.getDelegCred());
      Set<KerberosTicket> tickets = delegSub.getPrivateCredentials(KerberosTicket.class);
      3) The KerberosTicket EncryptedPart can be decrypted using the server's EncryptedKey above, with "usage = 2":
      for (Iterator ti = tickets.iterator(); ti.hasNext();) {
        KerberosTicket kbrTicket = (KerberosTicket)ti.next();
        Ticket ticket = new Ticket(kbrTicket.getEncoded());
        encTicketPart = new EncTicketPart(ticket.encPart.decrypt(privKey, 2));
      There's something wrong with my understanding, as I am always getting "KrbException: Checksum Failed." from the decrypt, from down in sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt. (Where can I get the source for sun.security.krb5 packages for debugging, btw?).

      Where am I going wrong? Can someone point me to example code that shows how to get from a KerberosTicket to a EncTicketPart?

      B Atkins
        • 1. Re: Decrypting encPart  example?  Checksum failed
          I'm confused on which key and principal are being made available to the server.
          Subject delegSub = GSSUtil.getSubject(con.getSrcName(), con.getDelegCred());
          Set<KerberosTicket> tickets = delegSub.getPrivateCredentials(KerberosTicket.class);
          The KerberosTicket returned from the delegated subject has a server principal of krbtgt@realm... Does this imply that the encrypted part of the ticket can only be decrypted by the secret key of that principal? Isn't the intent to allow it to be decrypted using the secret key of the server side of the context?

          Again, any pointers to materials that can clear this up for me, other forums where these questions may be more appropriate, or example implementation code would be most welcome.

          • 2. Re: Decrypting encPart  example?  Checksum failed
            Hi mate, I've been doing a load of kerberos/GSS stuff recently for a SOAP framework.

            The keys you get from the subject after logging in on the server are the secret keys of the server identity. These keys are (apparently) able to be used to decrypt the service ticket you get from the client. I assume that the acceptSecContext() method uses these keys.

            The delegated credentials you get (I haven't been able to get credential delegation working in my code), I assume, contains the TGT of the client, which can only be unencrypted using the client's secret keys (which you can't get on the server).

            You can print a kerberos ticket and you get heaps of info which may tell you more - this one I've listed below, you can clearly see that it is a TGT because the server principal is krbtgt/EXAMPLE.COM@EXAMPLE.COM.

            credential = class javax.security.auth.kerberos.KerberosTicket
            Ticket (hex) = 
            0000: 61 81 FA 30 81 F7 A0 03   02 01 05 A1 0D 1B 0B 45  a..0...........E
            0010: 58 41 4D 50 4C 45 2E 43   4F 4D A2 20 30 1E A0 03  XAMPLE.COM. 0...
            0020: 02 01 00 A1 17 30 15 1B   06 6B 72 62 74 67 74 1B  .....0...krbtgt.
            0030: 0B 45 58 41 4D 50 4C 45   2E 43 4F 4D A3 81 BE 30  .EXAMPLE.COM...0
            0040: 81 BB A0 03 02 01 03 A2   81 B3 04 81 B0 C1 A7 08  ................
            0050: F3 9B 26 68 C6 9F 60 90   D3 CF 4D EA 8A 18 6D 8E  ..&h..`...M...m.
            0060: B7 F1 9A 47 EE 11 1A 42   86 A4 D5 9A 0F 02 32 B0  ...G...B......2.
            0070: 7D E4 A7 D5 0E 20 0B C3   53 66 33 C3 D6 C6 BA 15  ..... ..Sf3.....
            0080: 34 02 4D A5 BD 00 1B 8E   B5 C0 A7 B1 1D D1 9C CD  4.M.............
            0090: AC 8C F7 01 67 AC 0B E0   1E 55 5C D6 17 EE 4B 46  ....g....U\...KF
            00A0: 0F 37 86 32 A0 28 55 CD   4D DA 1D AE 65 93 F8 9D  .7.2.(U.M...e...
            00B0: 31 2F 8C A9 48 12 EF EA   6E B1 E4 2B FE 00 30 DD  1/..H...n..+..0.
            00C0: B1 0F 47 C8 D7 AC 00 FD   D4 0B 31 12 D2 5C CC 95  ..G.......1..\..
            00D0: 51 26 E8 D3 6B AA 58 02   74 40 22 AB 47 21 82 99  Q&..k.X.t@".G!..
            00E0: 33 0D 45 3F 23 CE 6A A7   87 A1 FC 0C 9A 49 73 3D  3.E?#.j......Is=
            00F0: 53 E9 2A 0E 17 60 9C C5   83 B1 3C C8 AF 
            Client Principal = datahub/datahub.example.com/bully@EXAMPLE.COM
            Server Principal = krbtgt/EXAMPLE.COM@EXAMPLE.COM
            Session Key = EncryptionKey: keyType=3 keyBytes (hex dump)=
            0000: F1 52 AE 62 FD 7F D5 A1   
            Forwardable Ticket false
            Forwarded Ticket false
            Proxiable Ticket false
            Proxy Ticket false
            Postdated Ticket false
            Renewable Ticket false
            Initial Ticket false
            Auth Time = Wed Feb 20 15:25:36 NZDT 2008
            Start Time = Wed Feb 20 15:25:36 NZDT 2008
            End Time = Thu Feb 21 15:25:36 NZDT 2008
            Renew Till = Null 
            Client Addresses  Null 
            key alg = DES
            key fmt = RAW
            key exp = Thu Feb 21 15:25:36 NZDT 2008
            key type = 3
            name type = 1
            name = krbtgt/EXAMPLE.COM@EXAMPLE.COM
            realm = EXAMPLE.COM
            • 3. Re: Decrypting encPart  example?  Checksum failed
              Actually, I did figure this out. I apologize for not posting a resolution sooner.

              The Microsoft authorization data is actually delivered as part of the client ticket coming in during the GSS negotiation. You don't need the delegation ticket, which is completely separate and to be used for impersonation. It doesn't contain the PAC, nor any useful keys for getting at the PAC, as far as I can tell.

              The client ticket is what gets returned after the last (or only) iteration of the acceptSecContext() loop on the server side. That buffer you pass back and forth is the actual GSS PDU in DER ASN.1.

              Since GSS is generic and not Kerberos specific, you have to take the byte[] and turn it into a meaningful object. Handing that off to a DER parser you can then extract the KRB5 AP-REQ PDU, which in turn contains the ticket, which in turn contains the encrypted part encoded with either the session key or the server private key (depending on the apOptions field found in the AP-REQ PDU).

              It's messy decoding all that stuff, and decrypting the encrypted part, and even worse dealing with the PAC, which bears little to no resemblance to the Microsoft documentation of it's encoding. I actually consulted the Samba code to figure out how it was encoded (thanks, Samba gang for doing all that painful reverse engineering!!). Some have even speculated that M$ wrote bogus documentation as intentional disinformation. I prefer to believe it's the usual M$ incompetence rather than their usual malice.
              • 4. Re: Decrypting encPart  example?  Checksum failed
                I have a question related to this, that you might be able to help with:

                You mention that the encrypted part is sometimes encoded with the session key. How do you access the session key on the server side after doing an acceptSecContext() ?

                I'm grabbing the session key on the client side from the service ticket and using it to sign a SOAP message. But on the server side after acceptSecContext() is called the service ticket is not loaded into my subject, so I can't get to the session key to verify the message signature.

                • 5. Re: Decrypting encPart  example?  Checksum failed
                  I'm a little stale on this, since it was some time since I did the work, but here's what I believe you can do.

                  Once the session is established, you can get the server Subject from the ClientContext, I believe.

                  The getPrivateCredentials() method of the Subject will return a Set<Object> where the objects are either KerberosTicket or KerberosKey. The KerberosTicket object has a method, getSessionKey, which is a SecretKey. That's the shared key between the client and server for this session, iirc.

                  Does that help?
                  • 6. Re: Decrypting encPart  example?  Checksum failed
                    Thanks - that works on the client side, but server side it doesn't.

                    I've actually spoken to one of the guys who work on the security part of the JVM at Sun and they said that I can't access it server side through the GSS API. Seeing as this is required for the WS-Security Oasis standard, they might think about doing something about it in future JVMs.

                    So to access it I had to do my own build of the Sun kerberos and GSS Impl libraries and get it to create a SecretKeySpec for the session key, and drop it into the private credentials of the GSS Context during acceptSecContext().

                    This works fine, by the way, so problem solved - Full SOAP kerberos interop between .NET and Axis 2.
                    • 7. Re: Decrypting encPart  example?  Checksum failed
                      It works on the server side for me. I'm not actually using the session key to decode the EncryptedPart because the flag in the AP-REQ isn't set (I'm authenticating with MS AD), so I'm using the server private key. I guess it's possible that the session key I'm getting isn't the right key, but I am getting a session key that is a well formed key.

                      Basically, here's the steps (just the interesting parts):
                      LoginContext lc = new LoginContext("svr", new TextCallbackHandler());
                      Subject subj = lc.getSubject();
                      GSSManager manager = GSSManager.getInstance();
                      GSSContext con = manager.createContext((GSSCredential)null);
                      while ( !con.isEstablished() ) {
                          token = new byte[in.readInt()];
                          if (apReq== null) apReq = token;
                          token = con.acceptSecContext(token, 0, token.length);
                          if (token != null) {
                      Set<Object> creds = sub.getPrivateCredentials(Object.class);
                      for (Iterator<Object> i = creds.iterator(); i.hasNext();) {
                        Object cred = i.next();
                        if (cred instanceof KerberosTicket)
                          ticket = (KerberosTicket)cred;
                        else if (cred instanceof KerberosKey)
                          key = (KerberosKey)cred;
                      SecretKey secKey = ticket.getSessionKey();
                      EncryptionKey encKey = new EncryptionKey(secKey.getEncoded(), 23, new Integer(2));
                      I then use that encKey to decrypt the encPart of the ticket from the AP-REQ packet sent over from the client (e.g. before handing it to con.acceptSecContext(). It's ASN.1 DER, so you need to parse it to get the KRB5 ticket out, etc. I have examples of that too, if you need that. I'm not sure what you intend to do with the session key, since most of the work it is used for is done down in the APIs.
                      • 8. Re: Decrypting encPart  example?  Checksum failed
                        The token that gets passed to acceptSecContext() is actually encrypted with the Server's secret key, not the session key. The session key itself is hidden in the encrypted token that is passed to the acceptSecContext() method.

                        The KerberosKey you are getting out of the private credentials is actually the server's secret key that gets put there when the login is done (actually on my setup 5 different secret keys are put there all with different encryption types).

                        The reason I need the session key is that the .NET kerberos-enabled SOAP services, in addition to passing the AP-REQ kerberos ticket around, also digitally sign the SOAP message at the client end and verify this signature at the server end, using the session key.

                        As they are the only two parties who could ever know the session key (apart from the KDC), then it pretty much guarantees that the SOAP message is coming from either the client or the server - so there can be no spoofing or man in the middle trickery if the signature matches up.

                        It would be really useful to see your examples of decrypting the kerberos ticket, as to do this (I only had a few hours to get it working, so went for expediency) I had to download the Sun kerberos libraries and do my own build of all the kerberos stuff and the GSS implementation classes, then had to get it to bootstrap my own version of the Krb5 Mech factory to replace the Sun provider one (at runtime). Then when acceptSecContext() is called I grab the raw bytes of the EncryptionKey (which is the session key) from the Krb5Context and create a new SecretKeySpec with it and put it into the private credentials of the subject. This all works nicely, but a simpler way of decrypting it is a lot more desirable.

                        Thanks for the discussion, its good to see I'm not the only one who had tear my hair out trying to get on top of Kerberos.
                        • 9. Re: Decrypting encPart  example?  Checksum failed
                          The token that gets passed to acceptSecContext() is actually encrypted with the Server's secret key, not the session key.>
                          That is correct, unless apOptions says to use the session key (or so I'm lead to understand):
                          APOptions ::=   BIT STRING {
                          1       USE-SESSION-KEY The USE-SESSION-KEY option indicates
                                                                  that the ticket the client is
                                                                  presenting to a server is encrypted in
                                                                  the session key from the server's
                                                                  ticket-granting ticket. When this
                                                                  option is not specified, the ticket is
                                                                  encrypted in the server's secret key.
                          The session key itself is hidden in the encrypted token that is passed to the acceptSecContext() method.
                          That's correct, but it is decrypted during the authentication process and provided to the API as you see in my code. The session key is required by the Server so any wrapped traffic can be unwrapped, and visa versa.
                          The KerberosKey you are getting out of the private credentials is actually the server's secret key that gets put there when the login is done (actually on my setup 5 different secret keys are put there all with different encryption types).
                          No, I'm getting the session key from the KerberosTicket embedded in the credentials. If you look more closely, I am using the KerbrosTicket, not the KerberosKey, returned in the Set<Object>. The KerberosKey is indeed the server's private key.

                          Now, because the apOptions USE_SESSION_KEY is not set, I am indeed using the KerberosKey to decrypt the encPart, but the key in the Ticket is indeed the session key in that ticket, and is well formed (at least in my case, issued by AD).

                          That being said, I've never encountered the case were USE_SESSION_KEY was set, so I don't know if that key would work. Perhaps it isn't the session key you require.
                          As they are the only two parties who could ever know the session key (apart from the KDC), then it pretty much guarantees that the SOAP message is coming from either the client or the server - so there can be no spoofing or man in the middle trickery if the signature matches up.
                          The API hides most of the wrapping and unwrapping of the private traffic between client and server, so there usually isn't a need to use the session key in the ticket directly. But, it is provided as shown.

                          Of course, by relying on this, you are limiting yourself to only Kerberos authentication under GSS, which is intended to be generic, but that isn't a problem in my case.
                          • 10. ASN.1 decoding
                            Here is how I get the AP-REQ out of the byte[] received on the socket from the Client:
                               * Parses the token received from the Client
                               * (GSS-API InitialContextToken)
                               * Encoding: ASN.1 DER
                              private byte[] parseToken(byte[] token) throws Exception {
                                DerInputStream dis = new DerInputStream(token);
                                // get the GSS sequence (set is the same, and has constructed flag)
                                DerValue[] values = dis.getSet(token.length, true);
                                // Look for the AP_REQ tag [APPLICATION 14] (constructed)
                                for (int i=0; i<values.length; i++) {
                                  DerValue value = values;
                            if (value.isConstructed((byte)14)) {
                            return parseApReq(value.toDerInputStream(), value.length());

                            throw new Exception("No AP-REQ found in GSS InitialContextToken");
                            Here's the parsing of that AP-REQ:
                            * Parses tne AP-REQ PDU, which is the innerContextToken of
                            * the GSS InitialToken.
                            * Encoding: ASN.1/DER

                            private byte[] parseApReq(DerInputStream dis, int len) throws Exception {
                            // get the AP_REQ sequence (set is the same, and has constructed flag)
                            byte apOptions = 0;
                            DerValue ticket = null;

                            DerValue[] values = dis.getSet(len, true);
                            for (int i=0; i<values.length; i++) {
                            DerValue value = values[i];
                            if (value.isContextSpecific((byte)2)) {
                            // Get the bit string encapsulated in the
                            // context specific outter element.
                            apOptions = value.getData().getDerValue().getBitString()[0];
                            else if (value.isContextSpecific((byte)3)) {
                            // Get the value encapsulated in the
                            // context specific outter element.
                            ticket = value.getData().getDerValue();

                            if (ticket == null)
                            throw new Exception("No Ticket found in AP-REQ PDU");

                            return getAuthorizationData(new Ticket(ticket), serverSub, apOptions);
                            Here's the part that extracts the encPart and decrypts it.  The server subject passed in is from the LoginContext.getSubject() on the server side, after lc.login().
                            * Decrypt the EncryptedData into EncTicketPart
                            * Encoding: ASN.1/DER
                            private byte[] getAuthorizationData(Ticket ticket, Subject svrSub, byte ops)
                            throws Exception {

                            EncryptionKey key;
                            if (useSessionKey(ops))
                            key = getSessionKey(svrSub);
                            key = getPrivateKey(svrSub);

                            byte[] cleartext = ticket.encPart.decrypt(key, 2);
                            if (cleartext.length <= 0)
                            throw new Exception("zero length decrypt");

                            EncTicketPart encPart = new EncTicketPart(cleartext);
                            byte[] authPac = parseAuthData(encPart.authorizationData.asn1Encode(), 1);
                            return parseAuthData(authPac, 128);
                            Here's the key handling part, where *both* the Session and Private keys are acquired:
                            private EncryptionKey getSessionKey(Subject sub) throws Exception {
                            KerberosCreds creds = getKrbCreds(sub);
                            SecretKey secKey = creds.ticket.getSessionKey();
                            return new EncryptionKey(secKey.getEncoded(), 23, new Integer(2));

                            private EncryptionKey getPrivateKey(Subject sub) throws Exception {
                            KerberosCreds creds = getKrbCreds(sub);
                            return new EncryptionKey(creds.key.getEncoded(),
                            new Integer(2));

                            * Get credentials (KerberosKey and/or KerberosTicket) from a
                            * Subject
                            private KerberosCreds getKrbCreds(Subject sub) {
                            // Get the Client's Kerberos ticket from the private credentials
                            // of the subject.
                            KerberosCreds ret = new KerberosCreds();
                            Set<Object> creds = sub.getPrivateCredentials(Object.class);
                            for (Iterator<Object> i = creds.iterator(); i.hasNext();) {
                            Object cred = i.next();
                            if (cred instanceof KerberosTicket)
                            ret.ticket = (KerberosTicket)cred;
                            if (cred instanceof KerberosKey)
                            ret.key = (KerberosKey)cred;

                            return ret;
                            As you can see, this has turned a GSS implementation into something that's very Kerberos (and AD, for that matter) specific.
                            Edited by: batkins on Feb 22, 2008 12:14 PM
                            Edited by: batkins on Feb 22, 2008 12:17 PM                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                            • 11. Re: ASN.1 decoding
                              Pondering this some more (which I didn't need to do before, never confronted with the need to use the session key), it is likely that the session key from the Server subject is a key used between the server and the KDC (so my code is wrong if I should happen to get an AP-REQ with USE_SESSION_KEY set).

                              However, the session key should be in the encrypted part of the ticket presented by the Client (issued to it by the KDC, see below). That encrypted part would be decrypted using the server's private key, and would include the session key. The session key is then used to decrypt any encrypted traffic between the client and server as part of the established context.
                              Ticket ::=                    [APPLICATION 1] SEQUENCE {
                                                            tkt-vno[0]                   INTEGER,
                                                            realm[1]                     Realm,
                                                            sname[2]                     PrincipalName,
                                                            enc-part[3]                  EncryptedData
                              -- Encrypted part of ticket
                              EncTicketPart ::=     [APPLICATION 3] SEQUENCE {
                                                    flags[0]             TicketFlags,
                                        key[1]               EncryptionKey,
                                                    crealm[2]            Realm,
                                                    cname[3]             PrincipalName,
                                                    transited[4]         TransitedEncoding,
                                                    authtime[5]          KerberosTime,
                                                    starttime[6]         KerberosTime OPTIONAL,
                                                    endtime[7]           KerberosTime,
                                                    renew-till[8]        KerberosTime OPTIONAL,
                                                    caddr[9]             HostAddresses OPTIONAL,
                                                    authorization-data[10]   AuthorizationData OPTIONAL
                                 key       This field exists in the ticket and the KDC response and is
                                           used to pass the session key from Kerberos to the
                                           application server and the client.  The field's encoding is
                                           described in section 6.2.
                              Note that the client can't decrypt the encrypted part of this ticket, which it receives from the KDC, since it's encrypted using the server's private key. Only the server can decrypt the ticket and authenticator, which is how the server knows the client isn't spoofed (if the server trusts the KDC).

                              Edited by: batkins on Feb 22, 2008 12:34 PM
                              • 12. Re: ASN.1 decoding
                                I am trying the extract the client's SID from the PAC contained in the authorization-data. This thread has been very helpful and enabled me get to the point where I have the decryted ticket. But now I am not sure how to (reliabley) extract the PAC from the ASN1 encoded byte array returned by authorizationData.asn1Encode().

                                Method parseAuthData() in the code snippet above appears to perform this function. Could you possibly she some light on how this is done? Thanks.
                                • 13. Re: Decrypting encPart  example?  Checksum failed
                                  This seems to be a very useful thread with regards to Kerberos Token processing.

                                  My question is related to enabling credential delegation while using Kerberos token for WS-Security between a web service client and server.

                                  I have the basic stuff in -

                                  Client side:
                                  Setting the CredDelegState to true on the GSSContext
                                  Invoking initSecContext()

                                  Service side:
                                  acceptSecContext() (returns empty byte)
                                  context.isEstablished = true
                                  Trying to retrieve the credDelegState on server, it is always false. The delegCred object is null (nothing is delegated) and so are the srcName etc.

                                  I am not sure what I am missing in my code.

                                  Has anyone got Credential delegation to work in Java and over SOAP