Saphe Implementation - SaphePlugin.cpp
/**
 * 
 * Copyright (C) 2007-2008
 * Uri Sternfeld (saphesolution@yahoo.com)
 * All Rights Reserved
 *
 * Written by Uri Sternfeld
 * Last modified: 23/1/2008
 *
 **/
 
#include "SaphePlugin.h"
#include "resource.h"
 
#include <windowsx.h>
#include <winsock.h>
#include <time.h>
 
// Included to control the progress bar gadget
#include <commctrl.h>
 
// A trick learned from http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
// used to get the HINSTANCE of the current module, in order to load the dialog template
// from the binary
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
 
// Static variables: 
// Cryptographic Service Provider
// Instances map + map access guard
HCRYPTPROV nsSaphePluginInstance::crypt_prov;
CRITICAL_SECTION nsSaphePluginInstance::critical_section;
map<HWND, nsSaphePluginInstance*> nsSaphePluginInstance::current_instances;
 
////////////////////////////////////////////////////////////////////
 
// Show a runtime error
void ShowError(const char* error_msg) 
{
    MessageBoxA(0, error_msg, "SapheLogin error", MB_ICONERROR);
}
 
// Show a phishing attempt alert
void ShowPhishingAlert(const char* alert_msg) 
{
    MessageBoxA(0, alert_msg, "SapheLogin phishing attempt!", MB_ICONHAND);
}
 
// Disable the following:
//    - user name edit box
//    - password edit box
//    - OK button
//    - Cancel button
void DisableDialog(HWND hDlg) 
{
    Edit_Enable(GetDlgItem(hDlg, IDC_USER_NAME), FALSE);
    Edit_Enable(GetDlgItem(hDlg, IDC_PASSWORD), FALSE);
    Button_Enable(GetDlgItem(hDlg, IDOK), FALSE);
    Button_Enable(GetDlgItem(hDlg, IDCANCEL), FALSE);
}
 
// Enable the following:
//    - user name edit box
//    - password edit box
//    - OK button
//    - Cancel button
void EnableDialog(HWND hDlg) 
{
    Edit_Enable(GetDlgItem(hDlg, IDC_USER_NAME), TRUE);
    Edit_Enable(GetDlgItem(hDlg, IDC_PASSWORD), TRUE);
    Button_Enable(GetDlgItem(hDlg, IDOK), TRUE);
    Button_Enable(GetDlgItem(hDlg, IDCANCEL), TRUE);
}
 
//
// Callback procedure to handle the dialog box' messages
//
LRESULT CALLBACK PluginDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{    
    // The plugin instance is stored as a window long for the dialog box
    nsSaphePluginInstance* instance = (nsSaphePluginInstance*)GetWindowLong(hDlg, GWL_USERDATA);    
 
    switch (message)
    {
    // Sent on creation
    case WM_INITDIALOG:    
        // Make sure the dialog box is disabled
        DisableDialog(hDlg);
        return TRUE;    
 
    // Instructs the dialog box to instruct the plugin instance to retrieve the
    // real IP address of the user's machine. This is done so that the IP is retrieved
    // only when the dialog box is ready
    case WM_GET_IP:
        // Ask the browser to retrieve the real client IP address
        instance->AskForRealIP();
        return TRUE;
 
    // A button was clicked
    case WM_COMMAND:
        // Login button was clicked
        if (LOWORD(wParam) == IDOK) 
        {                
            // Make sure there is a user name
            CHAR user_name[EDIT_BOX_MAX_SIZE];
            if (GetDlgItemTextA(hDlg, IDC_USER_NAME, user_name, EDIT_BOX_MAX_SIZE) == 0) {
                Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Please enter username...");    
                return TRUE;
            }                        
 
            // Make sure there is a password
            CHAR password[EDIT_BOX_MAX_SIZE];            
            if (GetDlgItemTextA(hDlg, IDC_PASSWORD, password, EDIT_BOX_MAX_SIZE) == 0) {
                Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Please enter password...");                    
                return TRUE;
            }                        
 
            // The dialog is disabled during login
            DisableDialog(hDlg);
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Waiting for data from server...");
            SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_BAR), PBM_SETPOS, 0, 0);            
 
            // Go get 'em, tiger!
            instance->AskForSapheData(user_name, password);
 
            return TRUE;
        }
        // The cancel button was clicked
        else if (LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));    
            return TRUE;
        }
        // This should not happen - there are no other buttons...
        return FALSE;
 
    // A response containing the user's machine real IP address was returned
    case WM_GOT_IP: {            
        // Failed to get the IP?
        if (wParam == FALSE) {
            // Allow only to exit...
            Button_Enable(GetDlgItem(hDlg, IDCANCEL), TRUE);
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Failed to get real IP address!");
        }
        // Got the IP?
        else {
            // Re-enable the dialog
            EnableDialog(hDlg);
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Please enter user name and password...");
            SendMessage(GetDlgItem(hDlg, IDC_IPADDRESS), IPM_SETADDRESS, 0, instance->GetRealIP());
        }
        return TRUE;
    }
 
    // A response containing SapheData was returned and processed
    case WM_GOT_ENCRYPTED_DATA:        
 
        switch(wParam) {
        case SAPHE_SUCCESS:            
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Done... logging in...");    
            break;
        case SAPHE_NON_SECURE_LOGIN_URL:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Login URL is not secure!");
            break;            
        case SAPHE_STREAM_ERROR:            
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Failed to retrieve SapheLogin data from server!");
            break;        
        case SAPHE_UNKNOWN_STATUS_CODE:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Unrecognized status code");
            break;
        case SAPHE_USER_NAME_ERROR:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "The user name you entered does not exist!");
            break;
        case SAPHE_TOO_MANY_LOGIN_ATTEMPTS:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "The server detected too many consecutive failed login attempts");
            break;
        case SAPHE_PART_PARSE_ERROR:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Saphe data is corrupt!");
            ShowPhishingAlert("Saphe data is corrupt...\nThis can indicate a possible phishing attempt.");
            break;
        case SAPHE_SIGNATURE_ERROR:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Decryption failed. Maybe the password is wrong?");
            Edit_SetText(GetDlgItem(hDlg, IDC_PASSWORD), "");
            break;        
        case SAPHE_INVALID_URL_SIZE:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Unrecognized Saphe format!");
            break;
        case SAPHE_REQUESTED_URL_MISSING:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Unrecognized Saphe format!");
            break;
        case SAPHE_LOGIN_URL_MISSING:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Unrecognized Saphe format!");
            break;
        // Possible Phishing attempt thwarted!
        case SAPHE_CLIENT_IP_ERROR:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Client IP address does not match!");
            ShowPhishingAlert("Client IP reported by server does not match...\nThis can indicate a possible phishing attempt.");
            Edit_Enable(GetDlgItem(hDlg, IDC_USER_NAME), FALSE);
            Edit_Enable(GetDlgItem(hDlg, IDC_PASSWORD), FALSE);
            Button_Enable(GetDlgItem(hDlg, IDOK), FALSE);
            return TRUE;
        case SAPHE_REQUESTED_URL_ERROR:
            Edit_SetText(GetDlgItem(hDlg, IDC_STATUS), "Requested URL does not match!");
            ShowPhishingAlert("Requested URL reported by server does not match...\nThis can indicate a possible phishing attempt.");
            Edit_Enable(GetDlgItem(hDlg, IDC_USER_NAME), FALSE);
            Edit_Enable(GetDlgItem(hDlg, IDC_PASSWORD), FALSE);
            Button_Enable(GetDlgItem(hDlg, IDOK), FALSE);
            return TRUE;
        }
 
        EnableDialog(hDlg);
 
        return TRUE;    
    }
    return FALSE;
}
 
////////////////////////////////////////////////////////////////////
 
/**
 *
 * Plugin initialization.
 * Called when the browser starts.
 **/
NPError NS_PluginInitialize()
{
    // Create the critical section that protects the map
    InitializeCriticalSection(&nsSaphePluginInstance::critical_section);
 
    // Attempt to acquire the default CSP handle
    if (CryptAcquireContext(&nsSaphePluginInstance::crypt_prov, NULL, NULL, PROV_RSA_FULL, 0) == FALSE) {
        // If cannot acquire context - use none
        nsSaphePluginInstance::crypt_prov = NULL;        
    }    
 
    return NPERR_NO_ERROR;
}
 
/**
 *
 * Plugin shutdown.
 * Called when the browser closes.
 **/
void NS_PluginShutdown()
{
    DeleteCriticalSection(&nsSaphePluginInstance::critical_section);
 
    // Release the context
    if (nsSaphePluginInstance::crypt_prov != NULL) {
        CryptReleaseContext(nsSaphePluginInstance::crypt_prov, 0);
    }
}
 
/**
 *
 * Plugin instance initialization.
 * Called after a new instance was created.
 * Locates the target for the first Saphe transaction and makes sure its secure.
 **/
nsPluginInstanceBase * NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
    if(!aCreateDataStruct) {
        return NULL;  
    }    
 
    nsSaphePluginInstance* plugin = new nsSaphePluginInstance(aCreateDataStruct->instance);
 
    // Get the target server for the user name
    int16 i;
    for (i = 0 ; i < aCreateDataStruct->argc ; ++i) {
        if (stricmp(aCreateDataStruct->argn[i], SAPHE_URL) == 0) {
            // Donate now to prevent buffer overflows!            
            plugin->SetSapheURL(aCreateDataStruct->argv[i]);            
            break;
        }
    }
 
    if (i == aCreateDataStruct->argc) {
        ShowError("SapheLogin URL is missing!");
        delete plugin;
        return NULL;
    }
 
    // Make sure that the URL is secure
    if (IsSecureURL(plugin->GetSapheURL()) == false) {
        ShowError("SapheLogin URL is not secure!");
        delete plugin;
        return NULL;
    }
 
    return plugin;
}
 
/**
 *
 * Plugin instance destruction.
 **/
void NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
{
    if(aPlugin) {
        delete (nsSaphePluginInstance *)aPlugin;
    }
}
 
// ctor
nsSaphePluginInstance::nsSaphePluginInstance(NPP aInstance) : nsPluginInstanceBase(),
  mInstance(aInstance),
  mInitialized(FALSE)
{    
    mhParent = NULL;
    mhDialog = NULL;
    mhDialogProgressBar = NULL;
    mlClientRealIP = NULL;    
}
 
// dtor
nsSaphePluginInstance::~nsSaphePluginInstance()
{     
}
 
NPBool nsSaphePluginInstance::init(NPWindow* aWindow)
{        
    if(aWindow == NULL) {
        return FALSE;
    }
 
    HWND wnd = (HWND)aWindow->window;
    if (wnd == NULL) {
        return FALSE;  
    }
 
    // Take the parent of the current window (this is the current Firefox 'tab')
    mhParent = GetParent(wnd);        
 
    // Allow only one instance per parent/tab...        
    EnterCriticalSection(&critical_section);            
    if (current_instances.find(mhParent) != current_instances.end()) {        
        LeaveCriticalSection(&critical_section);
        return TRUE;
    }        
    current_instances.insert(pair<HWND,nsSaphePluginInstance*>(mhParent,this));    
    LeaveCriticalSection(&critical_section);     
 
    // Create a dialog box (from the HINSTANCE of the DLL)
    mhDialog = CreateDialog(HINST_THISCOMPONENT, (LPCTSTR)IDD_DIALOG1, mhParent, (DLGPROC)PluginDialogProc);    
    if (mhDialog == NULL) {
      char buf[31];
      sprintf(buf,"CreateDialog error: 0x%08X",GetLastError());
      ShowError(buf);
      return FALSE;
    }
 
    // Set the parameters of the new dialog:
 
    // The icon
    SendMessage(mhDialog, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(HINST_THISCOMPONENT, MAKEINTRESOURCE(IDI_ICON1)));
    // //SendMessage(mhDialog, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON1)));
    // The sizes of the edit boxes
    Edit_LimitText(GetDlgItem(mhDialog, IDC_USER_NAME), EDIT_BOX_MAX_SIZE-1);
    Edit_LimitText(GetDlgItem(mhDialog, IDC_PASSWORD), EDIT_BOX_MAX_SIZE-1);
    // The progress bar
    mhDialogProgressBar = GetDlgItem(mhDialog, IDC_PROGRESS_BAR);
 
    // associate the nsSaphePluginInstance object with a 'window long' so it can 
    // accessed by the dialog box callback procedures
    SetWindowLong(mhParent, GWL_USERDATA, (LONG)this);
    SetWindowLong(mhDialog, GWL_USERDATA, (LONG)this);    
 
    // Finally - show the dialog
    ShowWindow(mhDialog, SW_SHOW);    
 
    // The plugin is now initialized
    mInitialized = TRUE;
 
    // Instruct the dialog to ask for the client's IP address
    SendMessage(mhDialog, WM_GET_IP, 0, 0);
 
    return TRUE;
}
 
void nsSaphePluginInstance::shut()
{    
    // Kill the dialog box
    DestroyWindow(mhDialog);            
 
    // Clear this instance's entry from the map
    EnterCriticalSection(&critical_section);        
    map<HWND,nsSaphePluginInstance*>::iterator it = current_instances.find(mhParent);
    if (it != current_instances.end()) {        
        current_instances.erase(it);
    }
    LeaveCriticalSection(&critical_section);    
 
    mhParent = NULL;
    mhDialog = NULL;
    mhDialogProgressBar = NULL;
    mlClientRealIP = NULL;
 
    // The plugin instance is down
    mInitialized = FALSE;
}
 
NPBool nsSaphePluginInstance::isInitialized()
{
    return mInitialized;
}
 
//////////////////////
// Netscape API implementation
//////////////////////
 
NPError nsSaphePluginInstance::NewStream(NPMIMEType type, NPStream* stream, 
                            NPBool seekable, uint16* stype)         
{         
    // Don't handle streams with no stream info...
    if (stream->notifyData == NULL) {
        return NPERR_NO_ERROR; 
    }
 
    StreamInfo* stream_info = (StreamInfo*)stream->notifyData;
 
    // Is the size of the stream known? If so - allocate a buffer
    if (stream->end > 0) {
        stream_info->data_size = stream->end;
        stream_info->data = new byte[stream_info->data_size];
        stream_info->size_known = true;        
    }
    // If the size is unknown...
    else {                
        stream_info->size_known = false;
    }    
 
    // Update the progress bar
    SendMessage(mhDialogProgressBar, PBM_SETRANGE32, 0, stream->end);        
 
    return NPERR_NO_ERROR; 
}
 
NPError nsSaphePluginInstance::DestroyStream(NPStream *stream, NPError reason)   
{         
    // Do nothing
    return NPERR_NO_ERROR; 
}
 
int32 nsSaphePluginInstance::WriteReady(NPStream *stream)                      
{ 
    // Return maximum value
    return 0x0fffffff;     
}
 
int32 nsSaphePluginInstance::Write(NPStream *stream, int32 offset, 
                        int32 len, void *buffer)                    
{     
    // Don't handle streams with no stream info...
    if (stream->notifyData == NULL) {
        return len; 
    }
 
    StreamInfo* stream_info = (StreamInfo*)stream->notifyData;
 
    // Is there enough space for the data?
    if (offset+len > stream_info->data_size) {    
        byte* tmp = new byte[offset+len];        
        // Re-allocate the buffer
        if (stream_info->data != NULL) {
            memcpy(tmp, stream_info->data, stream_info->data_size);
            delete [] stream_info->data;            
        }
        stream_info->data_size = offset+len;        
        stream_info->data = tmp;        
    }
 
    // Copy the new data
    memcpy(stream_info->data + offset, (byte*)buffer, len);
 
    // Update the progress bar, if the size is known
    if (stream_info->size_known == true) {
        SendMessage(mhDialogProgressBar, PBM_SETPOS, offset+len, 0);        
    }
 
    return len; 
}
 
void nsSaphePluginInstance::URLNotify(const char* url, NPReason reason, void* notifyData)
{        
    // Don't handle any incoming streams unless they have stream info data    
    if (notifyData == NULL) {    
        return;
    }
 
    StreamInfo* stream_info = (StreamInfo*)notifyData;
 
    // Should we update the progress bar? (set it back to zero)
    if (stream_info->size_known == true) {
        SendMessage(mhDialogProgressBar, PBM_SETPOS, 0, 0);
    }
 
    // Handle responses to real IP address queries
    if (stream_info->id == StreamInfo::SAPHE_IP_DATA_ID) {
        HandleRealIPResponse(url, reason, stream_info);        
    }
    // Handle responses to SapheData from server
    else if (stream_info->id == StreamInfo::SAPHE_ENCRYPTED_PART_ID) {        
        HandleSapheDataResponse(reason, (StreamInfoSapheEncryptedPart*)notifyData);            
    }        
 
    // The StreamInfo dtor deletes the ->data field, if it was allocated
    delete stream_info;        
}
 
void nsSaphePluginInstance::SetSapheURL(const char* url)
{
    strncpy(mSapheURL, url, MAX_URL_SIZE);
}
 
void nsSaphePluginInstance::ReportPhishingAttemptToServer(const char* report_url)
{
    // Is the reporting URL empty?
    if (report_url[0] == 0) {
        return;
    }    
 
    // Can't report without IP
    if (mlClientRealIP == NULL) {
        return;
    }
 
    // Convert client IP to string representation
    in_addr tmp;
    tmp.S_un.S_addr = htonl(mlClientRealIP);
 
    // Prepare the post data
    char* post_data = new char[28+strlen(mSapheURL)];
    sprintf(post_data, "ip=%s;target=%s;", inet_ntoa(tmp), mSapheURL);
 
    // Send a POST message to the server. 
    // Any response (if any) will not be handled by the plugin (even though it
    // will be returned to the plugin by the browser) since URLNotify will not
    // be called as NPN_PostURL is not a 'XXXNotify' function.
    NPN_PostURL(mInstance, report_url, 0, strlen(post_data), post_data, 0);
 
    delete [] post_data;
}
 
void nsSaphePluginInstance::AskForRealIP()
{
    StreamInfoIP* stream_info = new StreamInfoIP();
    // Make sure the response is returned to the plugin by giving a NULL target
    NPN_GetURLNotify(GetNPPInstance(), USED_CLIENT_IP_URL, 0, (void*)stream_info);
}
 
void nsSaphePluginInstance::HandleRealIPResponse(const char* url, NPReason reason, StreamInfo* stream_info)
{
    if (reason != NPRES_DONE) {            
        SendMessage(mhDialog, WM_GOT_IP, FALSE, 0);
        return;
    }
 
    unsigned long address;    
    // Attempt to extract the IP from the data                        
    if (ExtractIPAddress(url, stream_info->data, &address) == false) {
        SendMessage(mhDialog, WM_GOT_IP, FALSE, 0);
        return;
    }
 
    mlClientRealIP = address;                
    SendMessage(mhDialog, WM_GOT_IP, TRUE, 0);    
}
 
void nsSaphePluginInstance::AskForSapheData(const char user_name[EDIT_BOX_MAX_SIZE], 
                                       const char password[EDIT_BOX_MAX_SIZE])
{
    StreamInfoSapheEncryptedPart* stream_info = new StreamInfoSapheEncryptedPart();                        
 
    strncpy(stream_info->user_name, user_name, EDIT_BOX_MAX_SIZE);
    strncpy(stream_info->password, password, EDIT_BOX_MAX_SIZE);
 
    // Generate challenge (strong, if possible)
    if ((nsSaphePluginInstance::crypt_prov == NULL) ||
        (CryptGenRandom(nsSaphePluginInstance::crypt_prov, CHALLENGE_SIZE, stream_info->client_challenge) == FALSE)) {
        // CryptGenRandom failed... generate (relatively) weak random
        srand(time(0));
        for (int i = 0 ; i < CHALLENGE_SIZE ; ++i) {
            stream_info->client_challenge[i] = rand()&0xFF;
        }
    }
 
    // Send a POST request
    char client_challenge_hex[(CHALLENGE_SIZE*2)+1];
    Hexlify(stream_info->client_challenge, CHALLENGE_SIZE, client_challenge_hex);
    char post_data[18+EDIT_BOX_MAX_SIZE+(CHALLENGE_SIZE*2)];
    sprintf(post_data, "user=%s;challenge=%s;", user_name, client_challenge_hex);
 
    // Make sure the response is returned to the plugin by giving a NULL target
    NPN_PostURLNotify(GetNPPInstance(), GetSapheURL(), NULL, 
                      strlen(post_data), post_data, false, (void*)stream_info);
}
 
void nsSaphePluginInstance::HandleSapheDataResponse(NPReason reason, 
                                               StreamInfoSapheEncryptedPart* saphe_info)
{
    // Was the stream read successfully?
    if (reason != NPRES_DONE) {            
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_STREAM_ERROR, 0);
        return;
    }                
 
    // Verify the magic at the beginning of the stream
    if ((saphe_info->data_size < SAPHE_MAGIC_SIZE+1) ||
        (strncmp((const char*)saphe_info->data, SAPHE_MAGIC, SAPHE_MAGIC_SIZE) != 0)) {
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_STREAM_ERROR, 0);
        return;
    }        
 
    // Check the status code...
    if (saphe_info->data[SAPHE_MAGIC_SIZE] == SAPHE_STATUS_NO_USER) {
        // User does not exist
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_USER_NAME_ERROR, 0);
        return;        
    }
    else if (saphe_info->data[SAPHE_MAGIC_SIZE] == SAPHE_STATUS_TOO_MANY_ATTEMPTS) {
        // User is blocked
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_TOO_MANY_LOGIN_ATTEMPTS, 0);
        return;        
    }
    else if (saphe_info->data[SAPHE_MAGIC_SIZE] != SAPHE_STATUS_DATA) {
        // Unknown status code
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_UNKNOWN_STATUS_CODE, 0);
        return;    
    }
 
    unsigned int data_size = saphe_info->data_size - SAPHE_MAGIC_SIZE - 1;
    char* data = (char*)(saphe_info->data + SAPHE_MAGIC_SIZE + 1);
 
    // Remove white spaces from the end
    while ((data_size > 0) && 
            ((data[data_size-1] == '\r')) ||
            ((data[data_size-1] == '\n')) ||
            ((data[data_size-1] == '\t')) ||
            ((data[data_size-1] == ' '))) {
        data_size--;
        data++;
    }
 
    // Convert the data from hex to binary
    unsigned char* enc_data = new unsigned char[data_size/2];
    if (Unhexlify(data, data_size, enc_data) == false) {
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_PART_PARSE_ERROR, 0);
        delete [] enc_data;
        return;
    }
 
    // Attempt to decrypt & parse the part
    unsigned long client_ip_address_little_endian;
    char url_requested_by_client[MAX_URL_SIZE+1];
    char login_url[MAX_URL_SIZE+1];
    char phishing_reports_url[MAX_URL_SIZE+1];
 
    SapheDataParseResult res = DecryptEncryptedPart(enc_data, data_size/2, 
                        saphe_info->password, saphe_info->client_challenge,
                        &client_ip_address_little_endian, url_requested_by_client,
                        login_url, phishing_reports_url);
 
    // No longer needed...
    delete [] enc_data;
 
    // Parsing/decryption failed...
    if (res != SAPHE_SUCCESS) {        
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, res, 0);
        return;                            
    }
 
    ////////////////////////////
    // Decryption successful! //
    ////////////////////////////            
 
    // Is the IP OK?    
    if (client_ip_address_little_endian != mlClientRealIP) {            
        ReportPhishingAttemptToServer(phishing_reports_url);
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_CLIENT_IP_ERROR, 0);
        return;
    }
 
    // Was the URL requested the same as the one that reached the server?
    if (stricmp(url_requested_by_client, mSapheURL) != 0) {        
        ReportPhishingAttemptToServer(phishing_reports_url);        
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_REQUESTED_URL_ERROR, 0);
        return;
    }
 
    // Is the login URL secure?
    if (IsSecureURL(login_url) == false) {        
        SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_NON_SECURE_LOGIN_URL, 0);
        return;
    }
 
    // Send success signal
    SendMessage(mhDialog, WM_GOT_ENCRYPTED_DATA, SAPHE_SUCCESS, 0);
 
    char post_data[17+(EDIT_BOX_MAX_SIZE*2)];
    sprintf(post_data, "user=%s;password=%s;", saphe_info->user_name, saphe_info->password);
 
    // Send the user name and password to the secure login URL.
    // Ask the browser to open the result in a the same windows. 
    // This will destroy the plugin instance and the dialog.
    NPN_PostURL(GetNPPInstance(), login_url, "_top", strlen(post_data), post_data, false);
}

Back to SaphePlugin implementation

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License