Page 1 of 1

Securing Hippa (ePHI) data MySQL solution review

Posted: Fri Feb 12, 2010 4:40 pm
by rufio1717
Problem: I have a client (small physicians office) that wants to allow patients to make/cancel appointments request prescription refills and view lab results. The guidelines for hipaa are sparse and can be viewed at http://www.hhs.gov/ocr/privacy/

Givens: My client is hosted on InMotions VPS. The full audit trails that are require to meet HIPAA guidelines is taken care using MySQL triggers.

Methods: OpenSSL, PHP Mcrypt Extension, SSL conenction

Solution:
1. A client signs up and inputs all their personal identifiable information (ePHI). The input is sterilized using mysql_real_escape_string() and validated on the server side. The patients ePHI is sent to the server using an SSL connection and sent using $_POST.
3. The ePHI data is encrypted using symmetric rijndael-256
4. The AES-256 bit encrypted data is encrypted using OpenSSL with the public key
5. The ePHI data that has been encrypted using first rijndael-256 encrypting and then the OpenSSL public key is store in a BLOB datatype column in a MySQL database.
6. The private key is store encrypted in a non-web root directory.
7. The encrypted ePHI can only be access by the office administrators. The office administrators logs in using their username and password. They then entered a pass phrase (example: The quick brown fox jumps over the lazy dog), which decrypts the hashed OpenSSL key. The ephi is then decrypted using the private OpenSSL key and the decrypted using the symmetric rijndael-256 bit encryption.

Code: Select all

 
//sample MySQL database table 
CREATE TABLE `patients`(
userid NOT NULL auto-increment PRIMARY KEY BIGINT(20),
telephone BLOB,
first_name BLOB,
last_name BLOB,
address BLOB); //BLOB is needed because the encrypted data need to be stored in binary unless base64_encoding is used, which I am against
 
//PHP code
<?php 
/* 
 * phpFreaksCrypto.class.php5 -> phpFreaksCrypto Class (PHP5) 
 */ 
 
 /** 
  * @author Dustin Whittle 
  * @version 0.01 
  */
 
if (isset($_SERVER['HTTPS']) )
{
    echo "SECURE: This page is being accessed through a secure connection.<br><br>";
}
else
{
    echo "UNSECURE: This page is being access through an unsecure connection.<br><br>";
}
 
class phpFreaksCrypto 
{ 
   
  private $td; 
     
  // this gets called when class is instantiated 
  public function __construct($key = 'tHsd2134SDgj12SDFiq3547SDFnsdk3298kl3', $iv = false, $algorithm = 'rijndael-256', $mode = 'ecb') 
  {
    if(extension_loaded('mcrypt') === FALSE) 
    { 
      $prefix = (PHP_SHLIB_SUFFIX == 'dll') ? 'php_' : ''; 
      dl($prefix . 'mcrypt.' . PHP_SHLIB_SUFFIX) or die('The Mcrypt module could not be loaded.'); 
    } 
 
    if($mode != 'ecb' && $iv === false) 
    { 
      /* 
        the iv must remain the same from encryption to decryption and is usually 
        passed into the encrypted string in some form, but not always. 
      */ 
      die('In order to use encryption modes other then ecb, you must specify a unique and consistent initialization vector.'); 
    } 
 
    // set mcrypt mode and cipher 
    $this->td = mcrypt_module_open($algorithm, '', $mode, '') ; 
 
    // Unix has better pseudo random number generator then mcrypt, so if it is available lets use it! 
    $random_seed = strstr(PHP_OS, "WIN") ? MCRYPT_RAND : MCRYPT_DEV_RANDOM; 
 
    // if initialization vector set in constructor use it else, generate from random seed 
    $iv = ($iv === false) ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), $random_seed) : substr($iv, 0, mcrypt_enc_get_iv_size($this->td)); 
 
    // get the expected key size based on mode and cipher 
    $expected_key_size = mcrypt_enc_get_key_size($this->td); 
 
    // we dont need to know the real key, we just need to be able to confirm a hashed version 
    $key = substr(hash('sha512',$key), 0, $expected_key_size); 
    
    // initialize mcrypt library with mode/cipher, encryption key, and random initialization vector 
    mcrypt_generic_init($this->td, $key, $iv); 
  } 
   
  public function encrypt($plain_string)
  {     
    /* 
      encrypt string using mcrypt and then encode any special characters 
      and then return the encrypted string 
    */ 
    return base64_encode(mcrypt_generic($this->td, $plain_string)); 
  } 
   
  public function decrypt($encrypted_string) 
  {  
    /* 
      remove any special characters then decrypt string using mcrypt and then trim null padding 
      and then finally return the encrypted string 
    */ 
    return trim(mdecrypt_generic($this->td, base64_decode($encrypted_string))); 
  }   
  // this function gets called when php garbage collection destroys the object 
  public function __destruct() 
  { 
    // shutdown mcrypt 
    mcrypt_generic_deinit($this->td); 
 
    // close mcrypt cipher module 
    mcrypt_module_close($this->td); 
  } 
} 
 
$crypto = new phpFreaksCrypto(); 
$string = 'blah.blah.blah'; 
$string2 = 'foo 124 !@$# foo  foo';
$encrypted_string = $crypto->encrypt($string); 
$decrypted_string = $crypto->decrypt($encrypted_string);
 
echo 'Original: ' . $string . '<br />';
echo 'Encrypted: ' . $encrypted_string . '<br />'; 
echo 'Decrypted: ' . $decrypted_string . '<br />'; 
 
//--------
//THIS IS ONLY DONE ONCE TO GENERATE THE PUBLIC AND PRIVATE KEY PAIR
// Create the keypair
$res=openssl_pkey_new();
 
// Get private key
//this private key will then be encrypted with rijndael-256 using a pass phrase like The quick brown fox jumps over the lazy dog
//the admins can access the private key by typing in the  pass phrase an unlocking the private key
openssl_pkey_export($res, $privatekey);
 
 
// Get public key
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];
//---------
 
echo "Private Key: $privatekey<br><br>Public Key:<BR>$publickey<BR><BR>";
 
$cleartext = $encrypted_string;
 
echo "Clear text: $cleartext<BR><BR>";
 
openssl_public_encrypt($cleartext, $crypttext, $publickey);
 
echo "Crypt text: $crypttext<BR><BR>";
 
openssl_private_decrypt($crypttext, $decrypted, $privatekey);
echo "OpenSSL decrypted text: $decrypted<br><br>";
$decrypted_string = $crypto->decrypt($decrypted);
echo "AES decrypted text: $decrypted_string<br><br>";
 
?>
 

Re: Securing Hippa (ePHI) data MySQL solution review

Posted: Wed Feb 17, 2010 1:48 pm
by rufio1717
I have been putting a lot of thought into this my solution does not work. Why? If someone hacks the web server they can change the script and collect all the patient information. The only solution that I can think of is using a three tier design (three servers). One server handles all interface. The 2nd server is an intermediary server. The 3rd server is a database server.

Re: Securing Hippa (ePHI) data MySQL solution review

Posted: Sat Feb 20, 2010 3:53 am
by kaisellgren
If you are about to store information that valuable, you should be asking/hiring someone to do it for you, and not implement it based on posts on forums.

Re: Securing Hippa (ePHI) data MySQL solution review

Posted: Fri Feb 26, 2010 9:29 pm
by yacahuma
Correct me if I am wrong BUT, HIPAA only applys when you are going to exchange information. Even if you have a hospital computer, it does not need to have any HIPPA certification, only when you transfer information from one system, to another, that is when the HIPPA stuff applys.

Who must comply?

All HIPAA covered entities must comply with the Security Rule. In general,
the standards, requirements, and implementation specifications of HIPAA
apply to the following covered entities:

Covered Health Care Providers - Any provider of medical or other
health care services or supplies who transmits any health information
in electronic form in connection with a transaction for which HHS has
adopted a standard.

Health Plans - Any individual or group plan that provides or pays the
cost of health care (e.g., a health insurance issuer and the Medicare
and Medicaid programs).


Health Care Clearinghouses - A public or private entity that
processes another entity’s health care transactions from a
standard format to a non-standard format, or vice-versa.


Medicare Prescription Drug Card Sponsors –A
nongovernmental entity that offers an endorsed discount drug
program under the Medicare Modernization Act. This fourth
category of “covered entity” will remain in effect until the drug
card program ends in 2006.


IS YOUR CLIENT ONE OF THESE????


BTW, kaisellgren, I disagree with your stament. Is good that he is asking in a forum. I for one, learn a lot here. You dont always get what you pay for anyway.