Hashcat capture file: Java parsing library

Native format of Hashcat password "recovery" utility

Application

["Hashcat", "aircrack-ng"]

File extension

hccapx

KS implementation details

License: Unlicense

This page hosts a formal specification of Hashcat capture file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for Java generated by Kaitai Struct depends on the Java runtime library. You have to install it before you can parse data.

The Java runtime library is published in the Maven Central Repository. Refer to the artifact page for instructions how to add it into your project with the build tool that you use.

Code

Parse a local file and get structure in memory:

Hccapx data = Hccapx.fromFile("path/to/local/file.hccapx");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
Hccapx data = new Hccapx(new ByteBufferKaitaiStream(someArray));

After that, one can get various attributes from the structure by invoking getter methods like:

data.records() // => get records

Java source code to parse Hashcat capture file

Hccapx.java

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

import io.kaitai.struct.ByteBufferKaitaiStream;
import io.kaitai.struct.KaitaiStruct;
import io.kaitai.struct.KaitaiStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;


/**
 * Native format of Hashcat password "recovery" utility
 * @see <a href="https://hashcat.net/wiki/doku.php?id=hccapx">Source</a>
 */
public class Hccapx extends KaitaiStruct {
    public static Hccapx fromFile(String fileName) throws IOException {
        return new Hccapx(new ByteBufferKaitaiStream(fileName));
    }

    public Hccapx(KaitaiStream _io) {
        this(_io, null, null);
    }

    public Hccapx(KaitaiStream _io, KaitaiStruct _parent) {
        this(_io, _parent, null);
    }

    public Hccapx(KaitaiStream _io, KaitaiStruct _parent, Hccapx _root) {
        super(_io);
        this._parent = _parent;
        this._root = _root == null ? this : _root;
        _read();
    }
    private void _read() {
        this.records = new ArrayList<HccapxRecord>();
        {
            int i = 0;
            while (!this._io.isEof()) {
                this.records.add(new HccapxRecord(this._io, this, _root));
                i++;
            }
        }
    }
    public static class HccapxRecord extends KaitaiStruct {
        public static HccapxRecord fromFile(String fileName) throws IOException {
            return new HccapxRecord(new ByteBufferKaitaiStream(fileName));
        }

        public HccapxRecord(KaitaiStream _io) {
            this(_io, null, null);
        }

        public HccapxRecord(KaitaiStream _io, Hccapx _parent) {
            this(_io, _parent, null);
        }

        public HccapxRecord(KaitaiStream _io, Hccapx _parent, Hccapx _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.magic = this._io.readBytes(4);
            if (!(Arrays.equals(magic(), new byte[] { 72, 67, 80, 88 }))) {
                throw new KaitaiStream.ValidationNotEqualError(new byte[] { 72, 67, 80, 88 }, magic(), _io(), "/types/hccapx_record/seq/0");
            }
            this.version = this._io.readU4le();
            this.ignoreReplayCounter = this._io.readBitsIntBe(1) != 0;
            this.messagePair = this._io.readBitsIntBe(7);
            this._io.alignToByte();
            this.lenEssid = this._io.readU1();
            this.essid = this._io.readBytes(lenEssid());
            this.padding1 = this._io.readBytes((32 - lenEssid()));
            this.keyver = this._io.readU1();
            this.keymic = this._io.readBytes(16);
            this.macAp = this._io.readBytes(6);
            this.nonceAp = this._io.readBytes(32);
            this.macStation = this._io.readBytes(6);
            this.nonceStation = this._io.readBytes(32);
            this.lenEapol = this._io.readU2le();
            this.eapol = this._io.readBytes(lenEapol());
            this.padding2 = this._io.readBytes((256 - lenEapol()));
        }
        private byte[] magic;
        private long version;
        private boolean ignoreReplayCounter;
        private long messagePair;
        private int lenEssid;
        private byte[] essid;
        private byte[] padding1;
        private int keyver;
        private byte[] keymic;
        private byte[] macAp;
        private byte[] nonceAp;
        private byte[] macStation;
        private byte[] nonceStation;
        private int lenEapol;
        private byte[] eapol;
        private byte[] padding2;
        private Hccapx _root;
        private Hccapx _parent;
        public byte[] magic() { return magic; }

        /**
         * The version number of the .hccapx file format.
         */
        public long version() { return version; }

        /**
         * Indicates if the message pair matching was done based on
         * replay counter or not.
         * 
         * Whenever it was set to 1 it means that the replay counter
         * was ignored (i.e. it was not considered at all by the
         * matching algorithm).
         * 
         * Hashcat currently does not perform any particular action
         * based on this bit, but nonetheless this information could be
         * crucial for some 3th party tools and for
         * analysis/statistics. There could be some opportunity to
         * implement some further logic based on this particular
         * information also within hashcat (in the future).
         */
        public boolean ignoreReplayCounter() { return ignoreReplayCounter; }

        /**
         * The message_pair value describes which messages of the 4-way
         * handshake were combined to form the .hccapx structure. It is
         * always a pair of 2 messages: 1 from the AP (access point)
         * and 1 from the STA (client).
         * 
         * Furthermore, the message_pair value also gives a hint from
         * which of the 2 messages the EAPOL origins. This is
         * interesting data, but not necessarily needed for hashcat to
         * be able to crack the hash.
         * 
         * On the other hand, it could be very important to know if
         * "only" message 1 and message 2 were captured or if for
         * instance message 3 and/or message 4 were captured too. If
         * message 3 and/or message 4 were captured it should be a hard
         * evidence that the connection was established and that the
         * password the client used was the correct one.
         */
        public long messagePair() { return messagePair; }
        public int lenEssid() { return lenEssid; }
        public byte[] essid() { return essid; }
        public byte[] padding1() { return padding1; }

        /**
         * The flag used to distinguish WPA from WPA2 ciphers. Value of
         * 1 means WPA, other - WPA2.
         */
        public int keyver() { return keyver; }

        /**
         * The final hash value. MD5 for WPA and SHA-1 for WPA2
         * (truncated to 128 bit).
         */
        public byte[] keymic() { return keymic; }

        /**
         * The BSSID (MAC address) of the access point.
         */
        public byte[] macAp() { return macAp; }

        /**
         * Nonce (random salt) generated by the access point.
         */
        public byte[] nonceAp() { return nonceAp; }

        /**
         * The MAC address of the client connecting to the access point.
         */
        public byte[] macStation() { return macStation; }

        /**
         * Nonce (random salt) generated by the client connecting to the access point.
         */
        public byte[] nonceStation() { return nonceStation; }

        /**
         * The length of the EAPOL data.
         */
        public int lenEapol() { return lenEapol; }
        public byte[] eapol() { return eapol; }
        public byte[] padding2() { return padding2; }
        public Hccapx _root() { return _root; }
        public Hccapx _parent() { return _parent; }
    }
    private ArrayList<HccapxRecord> records;
    private Hccapx _root;
    private KaitaiStruct _parent;
    public ArrayList<HccapxRecord> records() { return records; }
    public Hccapx _root() { return _root; }
    public KaitaiStruct _parent() { return _parent; }
}