NOEXPORT char *ntlm3(char *domain,
        char *user, char *password, char *phase2) {
    MD4_CTX md4;
    uint8_t *decoded; /* decoded reply from proxy */
    uint8_t phase3[146];
    uint8_t md4_hash[21];
    const size_t ntlm_len=24; /* length of the NTLM hash response */
    const size_t domain_len=strlen(domain);
    const size_t user_len=strlen(user);
    const size_t ntlm_off=64; /* start of the data block in version 2 */
    const size_t domain_off=ntlm_off+ntlm_len;
    const size_t user_off=domain_off+domain_len;
    const size_t end_off=user_off+user_len;

    /* setup the phase3 structure */
    if(end_off>sizeof phase3)
        return NULL;
    memset(phase3, 0, sizeof phase3);
    /* bytes 0-7: null-terminated NTLMSSP signature */
    strcpy((char *)phase3, "NTLMSSP");
    /* bytes 8-11: NTLM message type */
    phase3[8]=3;                    /* type: 3 */
    /* bytes 12-19: LM/LMv2 response */
    phase3[16]=(uint8_t)end_off;    /* LM response offset */
    /* bytes 20-27: NTLM/NTLMv2 response */
    phase3[20]=(uint8_t)ntlm_len;   /* NTLM response length */
    phase3[22]=(uint8_t)ntlm_len;   /* NTLM response length */
    phase3[24]=(uint8_t)ntlm_off;   /* NTLM response offset */
    /* bytes 28-35: target (domain/server) name */
    phase3[28]=(uint8_t)domain_len; /* domain length */
    phase3[30]=(uint8_t)domain_len; /* domain length */
    phase3[32]=(uint8_t)domain_off; /* domain offset */
    /* bytes 36-43: user name */
    phase3[36]=(uint8_t)user_len;   /* user length */
    phase3[38]=(uint8_t)user_len;   /* user length */
    phase3[40]=(uint8_t)user_off;   /* user offset */
    /* bytes 44-51: workstation name */
    phase3[48]=(uint8_t)end_off;    /* host offset */
    /* bytes 52-59: session key */
    phase3[56]=(uint8_t)end_off;    /* session key offset */
    /* bytes 60-63: flags */
    phase3[60]=2;                   /* flag: negotiate OEM */
    phase3[61]=2;                   /* flag: negotiate NTLM */

    /* calculate MD4 of the UTF-16 encoded password */
    MD4_Init(&md4);
    while(*password) {
        MD4_Update(&md4, password++, 1);
        MD4_Update(&md4, "", 1); /* UTF-16 */
    }
    MD4_Final(md4_hash, &md4);
    memset(md4_hash+16, 0, 5); /* pad to 21 bytes */

    /* decode the challenge and calculate the response */
    decoded=(uint8_t *)base64(0, phase2, (int)strlen(phase2)); /* decode */
    if(!decoded)
        return NULL;
    crypt_DES(phase3+ntlm_off,    decoded+24, md4_hash);
    crypt_DES(phase3+ntlm_off+8,  decoded+24, md4_hash+7);
    crypt_DES(phase3+ntlm_off+16, decoded+24, md4_hash+14);
    str_free(decoded);

    memcpy((char *)phase3+domain_off, domain, domain_len);
    memcpy((char *)phase3+user_off, user, user_len);

    return base64(1, (char *)phase3, (int)end_off); /* encode */
}
NOEXPORT char *ntlm3(char *domain,
        char *user, char *password, char *phase2) {
    MD4_CTX md4;
    uint8_t *decoded;  
    uint8_t phase3[146];
    uint8_t md4_hash[21];
    const size_t ntlm_len=24;  
    const size_t domain_len=strlen(domain);
    const size_t user_len=strlen(user);
    const size_t ntlm_off=64;  
    const size_t domain_off=ntlm_off+ntlm_len;
    const size_t user_off=domain_off+domain_len;
    const size_t end_off=user_off+user_len;

     
    if(end_off>sizeof phase3)
        return NULL;
    memset(phase3, 0, sizeof phase3);
     
    strcpy((char *)phase3, "NTLMSSP");
     
    phase3[8]=3;                     
     
    phase3[16]=(uint8_t)end_off;     
     
    phase3[20]=(uint8_t)ntlm_len;    
    phase3[22]=(uint8_t)ntlm_len;    
    phase3[24]=(uint8_t)ntlm_off;    
     
    phase3[28]=(uint8_t)domain_len;  
    phase3[30]=(uint8_t)domain_len;  
    phase3[32]=(uint8_t)domain_off;  
     
    phase3[36]=(uint8_t)user_len;    
    phase3[38]=(uint8_t)user_len;    
    phase3[40]=(uint8_t)user_off;    
     
    phase3[48]=(uint8_t)end_off;     
     
    phase3[56]=(uint8_t)end_off;     
     
    phase3[60]=2;                    
    phase3[61]=2;                    

     
    MD4_Init(&md4);
    while(*password) {
        MD4_Update(&md4, password++, 1);
        MD4_Update(&md4, "", 1);  
    }
    MD4_Final(md4_hash, &md4);
    memset(md4_hash+16, 0, 5);  

     
    decoded=(uint8_t *)base64(0, phase2, (int)strlen(phase2));  
    if(!decoded)
        return NULL;
    crypt_DES(phase3+ntlm_off,    decoded+24, md4_hash);
    crypt_DES(phase3+ntlm_off+8,  decoded+24, md4_hash+7);
    crypt_DES(phase3+ntlm_off+16, decoded+24, md4_hash+14);
    str_free(decoded);

    memcpy((char *)phase3+domain_off, domain, domain_len);
    memcpy((char *)phase3+user_off, user, user_len);

    return base64(1, (char *)phase3, (int)end_off);  
}