Saphe Implementation - SapheData.h
/**
 * 
 * Functions and definitions relevant to the Saphe content.
 *
 * Includes the following structures:
 *    StreamInfo - used to pass relevant information between the requester of 
 *                 a resource and the handler
 *    StreamInfoIP - contains data about client IP requests
 *    StreamInfoSapheEncryptedPart - contains data about SapheData requests
 * 
 * Includes the following functionality:
 *    CalculateEncryptedPartSize - Calculates the size needed for the SapheData part
 *                                 (used by the server)
 *    CreateEncryptedPart - Creates a SapheData part (used by the server)
 *    DecryptEncryptedPart - Decrypts & parses a SapheData part (used by the client)
 *    IsSecureURL - Decides if a given URL is secure (i.e: uses SSL)
 *    ExtractIPAddress - Extracts the IP address (as a dword) from a given HTML content
 *
 * Copyright (C) 2007-2008
 * Uri Sternfeld (saphesolution@yahoo.com)
 * All Rights Reserved
 *
 * Written by Uri Sternfeld
 * Last modified: 11/1/2008
 *
 **/
 
#ifndef __SAPHE_DATA_H__
#define __SAPHE_DATA_H__
 
#include "defs.h"
#include "CryptoStuff.h"
 
// This is the HTML key that marks the Saphe data retrieval URL
#define SAPHE_URL "saphe_url"    // The tag that specifies the URL to send user name to
#define SAPHE_MAGIC "SAPH"        // Identifies a SapheData content from the server
#define SAPHE_MAGIC_SIZE 4
#define MAX_URL_SIZE 1024        // Maximum size of any URL
#define EDIT_BOX_MAX_SIZE 64    // Maximum size of user name & password
 
/**
 * This struct contains information about a requested URL.
 * It is created by the requester and is passed to the browser
 * as opaque value.
 * Released by NPP_URLNotify after handling the response.
 **/
struct StreamInfo {
    enum STREAM_ID {
        SAPHE_IP_DATA_ID = 0x1000,
        SAPHE_ENCRYPTED_PART_ID,        
    };
 
    // ctor
    StreamInfo() { data = NULL; data_size = 0; }
    // dtor - make sure the data is released
    ~StreamInfo() { if (data != NULL) delete data; }
 
    STREAM_ID id;
    bool size_known;
    byte* data;
    unsigned int data_size;
};
 
/**
 * Used when asking for the client's IP address.
 **/
struct StreamInfoIP : public StreamInfo {
    // ctor
    StreamInfoIP() { 
        this->id = SAPHE_IP_DATA_ID;
    }
};
 
/**
 * Used when asking for Saphe data. 
 * Contains the user name, password and the client's random challenge.
 **/
struct StreamInfoSapheEncryptedPart : public StreamInfo {
    // ctor
    StreamInfoSapheEncryptedPart() {
        this->id = SAPHE_ENCRYPTED_PART_ID;
    }
 
    char user_name[EDIT_BOX_MAX_SIZE];
    char password[EDIT_BOX_MAX_SIZE];
    byte client_challenge[CHALLENGE_SIZE];
};
 
/**
Saphe data structure:
 
    magic value [4]    // 'SAPH'
    status code [1] // see SapheStatusCode below
    ------- start of Saphe Part -------
    encrypted buffer size [4]
    server challenge [16]
    initialization vector (IV) [16]
    plain hmac [20]    
    enc buffer [?]
        source ip [4]
        requested url size [2]
        requested url [?]        
        authentication url size [2]
        authentication url [?]    
        phishing report url size [2] // can be 0
        phishing report url [?]
**/
 
enum SapheStatusCode {
    SAPHE_STATUS_DATA = 'X',                // This message contains encrypted data
    SAPHE_STATUS_NO_USER = 'Y',                // The user ID does not exist
    SAPHE_STATUS_TOO_MANY_ATTEMPTS = 'Z',    // Too many failed login attempts
};
 
/**
 *
 * Calculates the length required for the output buffer that is passed to
 * CreateEncryptedPart. This is actually a constant size plus the lengths
 * of the three given URLs.
 *
 * This function is used by the SERVER.
 *
 * In:
 *    url_requested_by_client - the URL that was requested by the client in its 
 *        POST request
 *    phishing_reports_url - a URL that can be used possible Phishing attempts
 *    login_url - the URL that can be used to login after the server is authenticated 
 *        by the plugin
 * Returns:
 *    the size (in bytes) of the Saphe data (not including the magic and status fields)
 **/
unsigned int CalculateEncryptedPartSize(const char* url_requested_by_client,
                                        const char* phishing_reports_url,
                                        const char* login_url);
 
/**
 *
 * Creates the encrypted Saphe part returned to the client by the server (not
 * including the magic and status fields).
 *
 * This function is used by the SERVER.
 *
 * In:
 *    password - the null terminated user password
 *    client_challenge - the randomly generated buffer sent in the POST request
 *    server_challenge - a randomly generated buffer
 *    IV - the initialization vector to be used in the encryption process
 *    client_ip_address_little_endian - the IP address from which the POST request
 *        originated in little-endian format
 *    url_requested_by_client - the URL that was requested in the POST requset, 
 *        including the server name and HTTPS:// prefix
 *    login_url - the URL that will be used by the plugin to send the password to
 *        after the server is authenticated
 *    phishing_reports_url - an optional URL that can be used to send attempted
 *        Phishing reports to
 * Out:
 *    encrypted_part - should be the size returned by CalculateEncryptedPartSize
 * Returns:
 *    nothing
 **/
void CreateEncryptedPart(const char* password, 
                         const byte client_challenge[CHALLENGE_SIZE], 
                         const byte server_challenge[CHALLENGE_SIZE],
                         const byte IV[AES_BLOCK_SIZE],
                         unsigned long client_ip_address_little_endian,
                         const char* url_requested_by_client,                         
                         const char* login_url,
                         const char* phishing_reports_url,
                         byte* encrypted_part);
 
// Possible return values of DecryptEncryptedPart
enum SapheDataParseResult {
    SAPHE_SUCCESS = 0,        // Data was successfully decrypted & verified
    SAPHE_STREAM_ERROR,        // Stream transfer went bad
    SAPHE_UNKNOWN_STATUS_CODE,    // Illegal status code
    SAPHE_USER_NAME_ERROR,    // User does not exist on the server
    SAPHE_TOO_MANY_LOGIN_ATTEMPTS,    // The server detected too many login attempts
    SAPHE_PART_PARSE_ERROR,    // The structure of the part is corrupt        
    SAPHE_SIGNATURE_ERROR,    // Signature authentication failed    
    SAPHE_INVALID_URL_SIZE,    // URL size is too long
    SAPHE_REQUESTED_URL_MISSING, // The URL the user asked for does not exist in the data    
    SAPHE_LOGIN_URL_MISSING,    // The URL to send the password to is missing
    SAPHE_NON_SECURE_LOGIN_URL, // The login URL is not HTTPS (SSL)
    SAPHE_CLIENT_IP_ERROR,    // The IP the server got the connection from does not match our IP
    SAPHE_REQUESTED_URL_ERROR,  // The URL the user asked for does not match the data                
};
 
/**
 * 
 * Decrypts and parses the encrypted SapheData part received from the server.
 * Note that the server-side randomly generated challenge buffer and the 
 * initialization vector are read from the given SapheData buffer.
 *
 * This function is used by the CLIENT.
 *
 * In:
 *    encrypted_part - the encrypted data
 *    encrypted_part_size - the encrypted data size
 *    password - a null terminated string of the user's password
 *    client_challenge - the randomly generated challenge buffer of the client.
 * Out: 
 *    client_ip_address_little_endian - the IP from which the connection to the
 *        server originated
 *    url_requested_by_client - the URL that was requested from the server during
 *        the connection
 *    login_url - a URL that can be used to send the password to after the server
 *        is authenticated by the plugin
 *    phishing_reports_url - an optional URL to which Phishing reports may be sent
 *        (can be empty)
 * Returns:
 *    a SapheDataParseResult result, which can be one of the following:
 *        SAPHE_SUCCESS
 *        SAPHE_PART_PARSE_ERROR
 *        SAPHE_SIGNATURE_ERROR
 *        SAPHE_INVALID_URL_SIZE
 *        SAPHE_REQUESTED_URL_MISSING
 *        SAPHE_LOGIN_URL_MISSING 
 **/ 
SapheDataParseResult DecryptEncryptedPart(const byte* encrypted_part,
                                          unsigned int encrypted_part_size,
                                          const char* password, 
                                          const byte client_challenge[CHALLENGE_SIZE],                                          
                                          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]);
/**
 *
 * Checks if the URL begins with 'HTTPS://'
 *
 * In:
 *    url - the URL to be checked
 * Returns:
 *    true - if the URL is secure
 **/
bool IsSecureURL(const char* url);
 
// These URLS are used to discover the client's 'real' IP address
// (only the secured ones are used)
#define CLIENT_IP_URL1 "http://www.whatismyip.org/"
#define CLIENT_IP_URL2 "https://ip-address.domaintools.com/"
#define CLIENT_IP_URL3 "https://www.ip-adress.com/"
#define CLIENT_IP_URL4 "https://www.showmyip.com/"
//#define CLIENT_IP_URL5 "https://www.ip2location.com/?s=ipworld"
 
#define USED_CLIENT_IP_URL CLIENT_IP_URL4
 
/**
 *
 * Extracts the IP address as an unsigned long from the given HTML content according
 * to the URL it was retrieved from.
 * 
 * The format is dependant on the currently used server, and may change.
 * (this solution is not optimal)
 *
 * In:
 *    url - the URL from which the client's IP address was requested
 *    raw_data - the raw HTML data that was returned from the server
 * Out:
 *    extracted_ip - the IP that was extracted from the raw data (this value is 
 *        invalid if the functions returns 'false')
 * Returns:
 *    true - if the IP was extracted or false otherwise
 **/
bool ExtractIPAddress(const char* url, const byte* raw_data, unsigned long* extracted_ip);
 
#endif

Back to SapheData implementation

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