<?php

class Encryption
{
    private $masterIv = '1234567890123456'; // Master iv SECRET
    private $masterKey = 'kIl(Q2GZBRd79-}XpJ!(/uVs'; // Master key SECRET
    
    public function masterEncrypt($str)
    {
        $str = (string)$str;
        $ciphering = "AES-128-CTR";
        $ivLength = openssl_cipher_iv_length($ciphering);
        $options = 0;
        $encryption = openssl_encrypt($str, $ciphering, $this->masterKey, $options, $this->masterIv);
        
        return $encryption;
    }
    
    public function masterDecrypt($encryption)
    {
        $ciphering = "AES-128-CTR"; 
        $options = 0;
        $decryption = openssl_decrypt($encryption, $ciphering, $this->masterKey, $options, $this->masterIv);
        
        return $decryption;
    }
    
    /** Encrypteer gevoelige user data **/
    public function storeEncryptionIvAndKey($saveDir, $iv, $key)
    {
        if (!file_exists($saveDir))
            mkdir($saveDir, 0755, true);
        
        // Save encrypted Iv & key
        $ivFileName = $saveDir . "iv.txt";
        if(file_exists($ivFileName)) unlink($ivFileName);
        $ivFileHandle = fopen($ivFileName, 'w') or die("Kan encryptie iv bestand niet aanmaken.");
        fwrite($ivFileHandle, $iv);
        fclose($ivFileHandle);
        chmod($ivFileName, 0644);
        $keyFileName = $saveDir . "key.txt";
        if(file_exists($keyFileName)) unlink($keyFileName);
        $keyFileHandle = fopen($keyFileName, 'w') or die("Kan encryptie key bestand niet aanmaken.");
        fwrite($keyFileHandle, $key);
        fclose($keyFileHandle);
        chmod($keyFileName, 0644);
    }
    
    public function encrypt($str)
    {
        $str = (string)$str;
        $ciphering = "AES-128-CTR";
        $ivLength = openssl_cipher_iv_length($ciphering);
        $options = 0;
        $iv = openssl_random_pseudo_bytes($ivLength);
        $key = openssl_digest($this->randStr(), 'MD5', TRUE);
        $encryption = openssl_encrypt($str, $ciphering, $key, $options, $iv);
        
        return array('encryption' => $encryption, 'iv' => $iv, 'key' => $key);
    }
    
    /** Decrypteer gevoelige user data **/
    public function grabEncryptionIvAndKey($saveDir)
    {
        // Grab encrypted Iv & key
        $ivFileName = $saveDir . "iv.txt";
        $ivFile = fopen($ivFileName, "r");
        $iv = fgets($ivFile);
        $iv = file_get_contents($ivFileName);
        fclose($ivFile);
        $keyFileName = $saveDir . "key.txt";
        $keyFile = fopen($keyFileName, "r");
        $key = fgets($keyFile);
        $key = file_get_contents($keyFileName);
        fclose($keyFile);
        
        return array('iv' => $iv, 'key' => $key);
    }
    
    public function decrypt($encryption, $iv, $key)
    {
        $ciphering = "AES-128-CTR"; 
        $options = 0;
        $decryption = openssl_decrypt($encryption, $ciphering, $key, $options, $iv);
        
        return trim($decryption);
    }
}

$encryption = new Encryption();

define("PDO_DATABASE",  "db");
define("PDO_CONSTRING", "mysql:host=localhost;dbname=".PDO_DATABASE);
define("PDO_DBUSER",    "dbuser");
define("PDO_DBPASS",    "pwd");
define("DOC_ROOT", "/some/path/");

class Voorbeelden
{
    private $dbh = null;
    
    public function connect()
    {
        if($this->dbh == null)
        {
            try
            {
                $this->dbh = new PDO(PDO_CONSTRING, PDO_DBUSER, PDO_DBPASS);
                $this->dbh->setAttribute(PDO::ERRMODE_SILENT, PDO::ERRMODE_EXCEPTION);
            }
            catch(\PDOException $e)
            {
                $this->error = $e->getMessage();
                die("An error occured while connecting to the database.");
                exit(0);
            }
        }
    }
    
    function editNewEmail($newEmail)
    {
        // Gencrypteerde email opslaan in db
        global $encryption;
        $encrypted = $encryption->encrypt($newEmail);
            
        $saveDir = DOC_ROOT . "/app/Resources/userCrypts/".$_SESSION['UID']."/user/email/";
        $encryption->storeEncryptionIvAndKey($saveDir, $encrypted['iv'], $encrypted['key']);
        
        $statement = $this->dbh->prepre("UPDATE `user` SET `email`= :email WHERE `id` = :uid LIMIT 1");
        $statement->execute(array(':email' => $encrypted['encryption'], ':uid' => $_SESSION['UID']));
        
        // master encrypteren van email en serverside opslaan in 1 bestand voor alle actieve emails (nodig voor checken op bestaan) | Splits op bij big data!
        $masterEncrypted = $encryption->masterEncrypt($email);
        
        $saveDir = DOC_ROOT . "/app/Resources/masterCrypts/user/";
        $fileName = $saveDir . "emails.txt";
        $file = fopen($fileName, "r");
        $serializedEmails = fgets($file);
        $serializedEmails = file_get_contents($fileName);
        fclose($file);
        $emails = unserialize($serializedEmails);
        $emails[$_SESSION['UID']] = $masterEncrypted;
        
        if(file_exists($fileName)) unlink($fileName);
        $fileHandle = fopen($fileName, 'w') or die("Kan geheim bestand niet aanmaken.");
        fwrite($fileHandle, serialize($emails));
        fclose($fileHandle);
        chmod($fileName, 0644);
        
        return true;
    }
    
    public function checkEmailExists($email)
    {
        // Master geencrypteerde emails doorzoeken op een match
        global $encryption;
        $email = $encryption->masterEncrypt($email);
        
        $saveDir = DOC_ROOT . "/app/Resources/masterCrypts/user/";
        $fileName = $saveDir . "emails.txt";
        $file = fopen($fileName, "r");
        $serializedEmails = fgets($file);
        $serializedEmails = file_get_contents($fileName);
        fclose($file);
        $emails = unserialize($serializedEmails);
        
        $uid = array_search($email, $emails);
        
        $statement = $this->dbh->prepare("SELECT `id`, `username` FROM `user` WHERE `id`= :uid LIMIT 1"); //PDO call
        $statement->execute(array(':uid' => $uid));
        $row = $statement->fetch();
        if(isset($row['id']) && $row['id'] > 0)
            return true;
        
        return false;
    }
    
    public function getDecryptedEmailByUsername($username)
    {
        $statement = $this->dbh->prepare("SELECT `id`, `email` FROM `user` WHERE `username` = :username LIMIT 1"); // PDO call
        $statement->execute(array(':username' => $username));
        $row = $statement->fetch();
        if(isset($row['email']) && $row['email'] != "")
        {
            global $encryption;
            $saveDir = DOC_ROOT . "/app/Resources/userCrypts/".$row['id']."/user/email/";
            $cryptKeys = $encryption->grabEncryptionIvAndKey($saveDir);
            $decryptedEmail = $encryption->decrypt($row['email'], $cryptKeys['iv'], $cryptKeys['key']);
            
            return  $decryptedEmail;
        }
    }
}
