ntlm.java

来自「这是linux下ssl vpn的实现程序」· Java 代码 · 共 496 行 · 第 1/2 页

JAVA
496
字号
     * Creates the type 3 message using the given server nonce.  The type 3 message includes all the
     * information for authentication, host, domain, username and the result of encrypting the
     * nonce sent by the server using the user's password as the key.
     *
     * @param user The user name.  This should not include the domain name.
     * @param password The password.
     * @param host The host that is originating the authentication request.
     * @param domain The domain to authenticate within.
     * @param nonce the 8 byte array the server sent.
     * @return The type 3 message.
     * @throws AuthenticationException If {@encrypt(byte[],byte[])} fails.
     */
    public String getType3Message(String user, String password,
            String host, String domain, byte[] nonce)
    throws IOException {

        int ntRespLen = 0;
        int lmRespLen = 24;
        domain = domain.toUpperCase();
        host = host.toUpperCase();
        user = user.toUpperCase();
        byte[] domainBytes = domain.getBytes();
        byte[] hostBytes = host.getBytes();
        byte[] userBytes = user.getBytes();
        int domainLen = domainBytes.length;
        int hostLen = hostBytes.length;
        int userLen = userBytes.length;
        int finalLength = 64 + ntRespLen + lmRespLen + domainLen
            + userLen + hostLen;
        prepareResponse(finalLength);
        byte[] ntlmssp = "NTLMSSP".getBytes();
        addBytes(ntlmssp);
        addByte((byte) 0);
        addByte((byte) 3);
        addByte((byte) 0);
        addByte((byte) 0);
        addByte((byte) 0);

        // LM Resp Length (twice)
        addBytes(convertShort(24));
        addBytes(convertShort(24));

        // LM Resp Offset
        addBytes(convertShort(finalLength - 24));
        addByte((byte) 0);
        addByte((byte) 0);

        // NT Resp Length (twice)
        addBytes(convertShort(0));
        addBytes(convertShort(0));

        // NT Resp Offset
        addBytes(convertShort(finalLength));
        addByte((byte) 0);
        addByte((byte) 0);

        // Domain length (twice)
        addBytes(convertShort(domainLen));
        addBytes(convertShort(domainLen));

        // Domain offset.
        addBytes(convertShort(64));
        addByte((byte) 0);
        addByte((byte) 0);

        // User Length (twice)
        addBytes(convertShort(userLen));
        addBytes(convertShort(userLen));

        // User offset
        addBytes(convertShort(64 + domainLen));
        addByte((byte) 0);
        addByte((byte) 0);

        // Host length (twice)
        addBytes(convertShort(hostLen));
        addBytes(convertShort(hostLen));

        // Host offset
        addBytes(convertShort(64 + domainLen + userLen));

        for (int i = 0; i < 6; i++) {
            addByte((byte) 0);
        }

        // Message length
        addBytes(convertShort(finalLength));
        addByte((byte) 0);
        addByte((byte) 0);

        // Flags
        addByte((byte) 6);
        addByte((byte) 82);
        addByte((byte) 0);
        addByte((byte) 0);

        addBytes(domainBytes);
        addBytes(userBytes);
        addBytes(hostBytes);
        addBytes(hashPassword(password, nonce));
        return getResponse();
    }

    /**
     * Creates the LANManager and NT response for the given password using the
     * given nonce.
     * @param password the password to create a hash for.
     * @param nonce the nonce sent by the server.
     * @return The response.
     * @throws HttpException If {@link #encrypt(byte[],byte[])} fails.
     */
    private byte[] hashPassword(String password, byte[] nonce)
        throws IOException {
        byte[] passw = password.toUpperCase().getBytes();
        byte[] lmPw1 = new byte[7];
        byte[] lmPw2 = new byte[7];

        int len = passw.length;
        if (len > 7) {
            len = 7;
        }

        int idx;
        for (idx = 0; idx < len; idx++) {
            lmPw1[idx] = passw[idx];
        }
        for (; idx < 7; idx++) {
            lmPw1[idx] = (byte) 0;
        }

        len = passw.length;
        if (len > 14) {
            len = 14;
        }
        for (idx = 7; idx < len; idx++) {
            lmPw2[idx - 7] = passw[idx];
        }
        for (; idx < 14; idx++) {
            lmPw2[idx - 7] = (byte) 0;
        }

        // Create LanManager hashed Password
        byte[] magic = {
            (byte) 0x4B, (byte) 0x47, (byte) 0x53, (byte) 0x21,
            (byte) 0x40, (byte) 0x23, (byte) 0x24, (byte) 0x25
        };

        byte[] lmHpw1;
        lmHpw1 = encrypt(lmPw1, magic);

        byte[] lmHpw2 = encrypt(lmPw2, magic);

        byte[] lmHpw = new byte[21];
        for (int i = 0; i < lmHpw1.length; i++) {
            lmHpw[i] = lmHpw1[i];
        }
        for (int i = 0; i < lmHpw2.length; i++) {
            lmHpw[i + 8] = lmHpw2[i];
        }
        for (int i = 0; i < 5; i++) {
            lmHpw[i + 16] = (byte) 0;
        }

        // Create the responses.
        byte[] lmResp = new byte[24];
        calcResp(lmHpw, nonce, lmResp);

        return lmResp;
    }

    /**
     * Takes a 21 byte array and treats it as 3 56-bit DES keys.  The 8 byte
     * plaintext is encrypted with each key and the resulting 24 bytes are
     * stored in the results array.
     *
     * @param keys The keys.
     * @param plaintext The plain text to encrypt.
     * @param results Where the results are stored.
     * @throws AuthenticationException If {@link #encrypt(byte[],byte[])} fails.
     */
    private void calcResp(byte[] keys, byte[] plaintext, byte[] results)
        throws IOException {
        byte[] keys1 = new byte[7];
        byte[] keys2 = new byte[7];
        byte[] keys3 = new byte[7];
        for (int i = 0; i < 7; i++) {
            keys1[i] = keys[i];
        }

        for (int i = 0; i < 7; i++) {
            keys2[i] = keys[i + 7];
        }

        for (int i = 0; i < 7; i++) {
            keys3[i] = keys[i + 14];
        }
        byte[] results1 = encrypt(keys1, plaintext);

        byte[] results2 = encrypt(keys2, plaintext);

        byte[] results3 = encrypt(keys3, plaintext);

        for (int i = 0; i < 8; i++) {
            results[i] = results1[i];
        }
        for (int i = 0; i < 8; i++) {
            results[i + 8] = results2[i];
        }
        for (int i = 0; i < 8; i++) {
            results[i + 16] = results3[i];
        }
    }

    /**
     * Converts a given number to a two byte array in little endian order.
     * @param num the number to convert.
     * @return The byte representation of <i>num</i> in little endian order.
     */
    private byte[] convertShort(int num) {
        byte[] val = new byte[2];
        String hex = Integer.toString(num, 16);
        while (hex.length() < 4) {
            hex = "0" + hex;
        }
        String low = hex.substring(2, 4);
        String high = hex.substring(0, 2);

        val[0] = (byte) Integer.parseInt(low, 16);
        val[1] = (byte) Integer.parseInt(high, 16);
        return val;
    }

    /**
     * @return Returns the credentialCharset.
     */
    public String getCredentialCharset() {
        return credentialCharset;
    }

    /**
     * @param credentialCharset The credentialCharset to set.
     */
    public void setCredentialCharset(String credentialCharset) {
        this.credentialCharset = credentialCharset;
    }

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?