Monday, March 16, 2015

.NET Cryptography: A Quick And Simplified View

This is just a quick and simplified view of the .NET cryptography generally used.

Of course, this is really a broad and deep subject, it just depends on how deep are you willing to dive into. ;)


Algorithms Preferences
1. Rijndael (strongest)
2. TripleDES (strong)
3. DES, RC2 (weak, please do not use if not necessary)


Rijndael Encryption/Decryption
- Algorithm : RijndaelManaged (C#)
- Mode : CBC
- Padding Mode : PKCS7
- Key : 32 ASCII chars (32 bytes / 256 bits)
- IV : 16 ASCII chars (16 bytes / 128 bits)
- Same as AES-256

- To use RijndaelManaged as AES (or AES compliant):
- Mode : CBC
- Key Size : 128 / 192 / 256 bits (default 256 bits, means AES-256)
- Block Size : 128 bits (default)

- The Differences Between Rijndael and AES.


TripleDES Encryption/Decryption
- Algorithm : TripleDESCryptoServiceProvider (C#)
- Mode : CBC
- Padding Mode : PKCS7
- Key : 24 ASCII chars (24 bytes / 192 bits)
- IV : 8 ASCII chars ( 8 bytes / 64 bits)



If you find this post helpful, would you buy me a coffee?


Sunday, March 15, 2015

Logging To File Or Email In PHP

Logging is one of the most important things in software engineering to record important code execution, as well as for debugging.

This is a simple PHP function for logging error and info, by sending email notification or logging to file, with the option to record a different timezone:

<?php

/**
* Logs an error.
*/
function logError($logMessage, $sourceFile)
{
    logInfo($logMessage, $sourceFile, "", true);
}

/**
* Logs an information.
*/
function logInfo($logMessage, $sourceFile, $logTtle = "", $isError = false)
{
    $logEmail       = "admin@example.com";      // Email address to send the logging message. Set to empty to disable it.
    $logFile        = "";                       // File name to store the logging message. Set to empty to disable it.
    $logTimezone    = "Europe/London";          // Set the additional datetime timezone shown in the logging message. Put empty to only show the default.
    
    $now            = new DateTime();           // Get current datetime in the default timezone.
    
    $logMsg = '[' . $now->format("Y-m-d H:i:s e") . ']' . "\r\n" . '[' . $sourceFile . ']' . "\r\n" . $logMessage . "\r\n\r\n";
    
    if ($logTimezone != "")
    {
        // Convert $now to the provided timezone and append at front as additional datetime.
        $now->setTimezone(new DateTimeZone($logTimezone));
        $logMsg = '[' . $now->format("Y-m-d H:i:s e") . '] ' . $logMsg;
        // ==
    }
    
    if ($logFile != "") {
        if ($isError)
            error_log($logMsg, 3, $logFile);
        else
            file_put_contents($logFile, $logMsg, FILE_APPEND | LOCK_EX);
    }
    
    if ($logEmail != "") {
        if ($isError)
            error_log($logMsg, 1, $logEmail);
        else
            mail($logEmail, $logTtle, $logMsg, "From: Notification Admin <noti@example.com>");
    }
}

Usage example:

<?php

try
{
    ...
    ...
    logInfo("Process completed successfully.", __FILE__, "Process Completed");
}
catch(Exception $e)
{
    logError("Process Exception: " . $e->getMessage() . ". Exception on line: " . $e->getLine(), __FILE__);
    exit;
}
?>


If you find this post helpful, would you buy me a coffee?


Tuesday, March 10, 2015

Update An Existing Configuration File In PHP

In PHP, it's a widely used practice to set a site's configuration details by defining constants in a separate "config" file.

This config file mostly contains important data such as security keys, database connections, paths, debug and logging information, and many more.

Normally, the config file contents are manually set by hand. However, we can also update or add contents from another new config file into an existing config file, which is being demonstrated in the following script. This script will update an existing defined constant with the new value, or add the constant if it doesn't exist. (Please change the FOO_CONFIG and NEW_FOO_CONFIG constants on top to your file path):

<?php

// Define the foo config file paths.
define('FOO_CONFIG',     __DIR__ . '/foo-config.php');          // The existing foo config file.
define('NEW_FOO_CONFIG', __DIR__ . '/new-foo-config.php');      // The new foo config file.
// ==

updateFooConfig();
return;

/**
* Updates NEW_FOO_CONFIG contents into existing FOO_CONFIG file.
*/
function updateFooConfig()
{
    try
    {
        $fooConfig        = file_get_contents(FOO_CONFIG);              // Read from existing FOO_CONFIG contents into string.
        $newFooConfig     = file_get_contents(NEW_FOO_CONFIG);          // Read from the NEW_FOO_CONFIG contents into string.
        
        $newFooConfigLine = strtok($newFooConfig, "\r\n");              // Read each line in the NEW_FOO_CONFIG string.
        while ($newFooConfigLine !== false)
        {
            // Note: Patterns must be enclosed with delimiters, e.g. "/".
            
            if (preg_match("/\s*define\s*\(\s*('.*?')\s*,\s*('*.*?'*)\s*\)\s*;\s*/", $newFooConfigLine, $matches))              // If the NEW_FOO_CONFIG line is a define(...).
            {
                if (preg_match("/\s*define\s*\(\s*" . $matches[1] . "\s*,\s*('*.*?'*)\s*\)\s*;\s*/", $fooConfig, $matches2))    // If FOO_CONFIG string contains the same define(...) constant.
                    $fooConfig = str_replace(trim($matches2[0]), trim($matches[0]), $fooConfig);                                // Replace FOO_CONFIG string with this NEW_FOO_CONFIG line string.
                else
                    $fooConfig = $fooConfig . PHP_EOL . $newFooConfigLine;                                                      // Append this NEW_FOO_CONFIG line to FOO_CONFIG string if not found.
            }

            $newFooConfigLine = strtok( "\r\n" );                       // Read next line in NEW_FOO_CONFIG string.
        }
        
        if (file_put_contents(FOO_CONFIG, $fooConfig) === false)        // Wrtie the FOO_CONFIG string back to it's file, overwrite existing.
            throw new Exception("Foo config file '" . FOO_CONFIG . "' cannot be written.");
    }
    catch(Exception $e)
    {
        // TODO: Throw or log the exception.
        exit;
    }
}


If you find this post helpful, would you buy me a coffee?


Wednesday, March 4, 2015

MySQL Drop Foreign Key If Exists

If you tried to drop a foreign key from a table, and the foreign key does not exist, you may hit to error such as:

Error Code: 1025
Error on rename of '.\mydatabase\mytable' to '.\mydatabase\#sql2-xxxx-xx' (errno: 152)

This may not be an issue if the statement is executed manually, but it's troublesome if the statement is part of a larger script that runs in batch (without using the --force option).

Currently there is no way to check for "IF EXISTS" before dropping the foreign key. However, you could create a temporary procedure to achieve that:


/* Purpose: Drop foreign key if exists, without generating errors.
 * Usage  : Set in the 'Modify - Begin/End' section below, then include this script into the real script.
*/

DROP PROCEDURE IF EXISTS tmp_drop_foreign_key;

DELIMITER $$

CREATE PROCEDURE tmp_drop_foreign_key(IN tableName VARCHAR(64), IN constraintName VARCHAR(64))
BEGIN
    IF EXISTS(
        SELECT * FROM information_schema.table_constraints
        WHERE 
            table_schema    = DATABASE()     AND
            table_name      = tableName      AND
            constraint_name = constraintName AND
            constraint_type = 'FOREIGN KEY')
    THEN
        SET @query = CONCAT('ALTER TABLE ', tableName, ' DROP FOREIGN KEY ', constraintName, ';');
        PREPARE stmt FROM @query; 
        EXECUTE stmt; 
        DEALLOCATE PREPARE stmt; 
    END IF; 
END$$

DELIMITER ;

/* ========= Modify - Begin. ========= */
CALL tmp_drop_foreign_key('table1', 'foreign_key_1');
-- Add CALL statements for any other tables and foreign keys here.
/* ========= Modify - End. =========== */

DROP PROCEDURE tmp_drop_foreign_key;

To use it, simple change the 'Modify - Begin/End' section in the script, then include this script into your real script to be executed.


If you find this post helpful, would you buy me a coffee?


Returning Database Server Current Date And Time

Life would be easy if all database providers use the same SQL syntax for all data management tasks. Unfortunately in the real world, that's not the case. If you're not using an O/R Mapper (or sometimes because of the limitation of it), then you have to resort to write different SQL statements for each database provider for the same task.

The following list shows the SQL syntax to get the current date and time from a database server, depending on the database provider type (all datetime are returned in "yyyyMMddHHmmss" format):

MySQL:
SELECT CONVERT(DATE_FORMAT(CURRENT_TIMESTAMP, '%Y%m%d%H%i%s'), CHAR(14));

MySQL (for supported version which CONVERT is not needed):
SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y%m%d%H%i%s');

Microsoft SQL Server:
SELECT LTRIM(RTRIM(CONVERT(VARCHAR(8),CURRENT_TIMESTAMP,112)+REPLACE(CONVERT(VARCHAR(8),CURRENT_TIMESTAMP,108),':','')));

Oracle:
SELECT TRIM(TO_CHAR(systimestamp, 'YYYYMMDDHH24MISS')) FROM dual;

SQLite:
SELECT STRFTIME('%Y%m%d%H%M%S',CURRENT_TIMESTAMP, 'localtime');



If you find this post helpful, would you buy me a coffee?


Sunday, September 15, 2013

Object And XML Serialization

In .Net, we can serialize and deserialize an object to/from an XML string using XmlSerializer.

The following methods provide easy ways to do this, with overloads that accept an existing instance of XmlSerializer if there is any.
  • Note: To avoid any performance hit, it's always better to use back an existing instance of XmlSerializer for the same object type if possible.

using System.IO;
using System.Xml;
using System.Xml.Serialization;

...

/// <summary>
/// Serializes an object to XML string.
/// </summary>
/// <param name="obj">Object to be serialized.</param>
/// <returns>Serialized XML string.</returns>
public static string SerializeObjectToXML(object obj)
{
    return SerializeObjectToXML(obj, null);
}

/// <summary>
/// Serializes an object to XML string.
/// </summary>
/// <param name="obj">Object to be serialized.</param>
/// <param name="serializer">An XmlSerializer instance to be used. If null, a new instance will be used.</param>
/// <returns>Serialized XML string.</returns>
public static string SerializeObjectToXML(object obj, XmlSerializer serializer)
{
    string xmlString;

    using (StringWriter stringWriter = new StringWriter())
    {
        if (serializer == null)
            serializer = new XmlSerializer(obj.GetType());

        serializer.Serialize(stringWriter, obj);
        stringWriter.Flush();
        xmlString = stringWriter.ToString();
    }

    return xmlString;
}

/// <summary>
/// Deserializes XML string to an object.
/// </summary>
/// <param name="xmlString">Serialized XML string.</param>
/// <param name="objType">Type of object to deserialize.</param>
/// <returns>Object deserialized from XML.</returns>
public static object DeserializeXMLToObject(string xmlString, Type objType)
{
    return DeserializeXMLToObject(xmlString, objType, null);
}

/// <summary>
/// Deserializes XML string to an object.
/// </summary>
/// <param name="xmlString">Serialized XML string.</param>
/// <param name="objType">Type of object to deserialize.</param>
/// <param name="serializer">An XmlSerializer instance to be used. If null, a new instance will be used.</param>
/// <returns>Object deserialized from XML.</returns>
public static object DeserializeXMLToObject(string xmlString, Type objType, XmlSerializer serializer)
{
    object obj = null;

    using (StringReader stringReader = new StringReader(xmlString))
    {
        if (serializer == null)
            serializer = new XmlSerializer(objType);

        obj = serializer.Deserialize(stringReader);
        stringReader.Close();
    }

    return obj;
}


If you find this post helpful, would you buy me a coffee?


Thursday, September 12, 2013

Regasm COM Interop Assembly With .Net Installer Project

COM Interop allows COM developers to access managed objects as easily as they access other COM objects. COM Interop provides a specialized utility (RegAsm.exe) that exports the managed types into a type library and registers the managed component as a traditional COM component.

To manually register a COM Interop assembly using RegAsm, we typically would do the following (assuming MyCom.COM.dll is an assembly that implements COM Interop for the managed MyCom.dll assembly):
  • Copy MyCom.COM.dll and MyCom.dll (and any other local assemblies) to a folder.
  • Run in VS command prompt: regasm [yourpath]\MyCom.COM.dll /tlb /codebase

However, it's also possible to include the Regasm process into a .Net Installer. Obviously this is the most ideal solution for easy distribution.

To implement this, I've largely benefited from Leon Mayne's blog Regasm /codebase for an installer project.

Below is a direct extract from the blog article about things to take note:

  • Making sure you do not use project references when adding your files to the installer. Use direct file references instead
  • Do the same for referenced files that are included automatically, as they do not get dropped in the obj folder and cause problems. Just exclude them from the project and then add them manually to the installer output
  • Make sure you have a type library for your dll and that this is included in the installer and set to register for COM
  • Make sure your dll is set to register for COM (duh)

Note: The first and second points may differ for some situations, as from my experience, I could use project references without any problem.

And another direct extract from the blog article that clearly stated the steps to perform:

  1. In your main project (the one containing the class you want to register), right click the project file and select Add / New Item and select Installer Class. Call it something like clsRegisterDll.cs
  2. In the designer that appears, click 'Click here to switch to code view' or right click the clsRegisterDll.cs file in solution explorer and select View Code
  3. Replace the code in the window with the code listed below, and make sure you change 'YourNamespace'. This has to match with the namespace in the clsRegisterDll.Designer.cs file.
  4. Compile your project
  5. In your installer, make sure you have added your dll to the Application Folder, and then right-click the installer project and select View / Custom Actions
  6. Right-click Install, and then click Add Custom Action
  7. Double click on Application Folder, and then on your dll
  8. Do the same for the Commit action
  9. Build and test your installer

Ok, now for the clsRegisterDll.cs class. In my implementation, I've renamed this class to RegasmTlbInstaller.cs, made some code changes, and also added overrides for Rollback and Uninstall.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Collections;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;

namespace YourNamespace
{
    /// <summary>
    /// An installer class to run regasm /tlb /codebase on the COM DLL (register and un-register).
    /// </summary>
    [RunInstaller(true)]
    public partial class RegasmTlbInstaller : Installer
    {
        public RegasmTlbInstaller()
        {
            InitializeComponent();
        }

        [SecurityPermission(SecurityAction.Demand)]
        public override void Install(IDictionary savedState)
        {
            base.Install(savedState);
        }

        /// <summary>
        /// Runs regasm /tlb /codebase to create and register the TLB file.
        /// </summary>
        [SecurityPermission(SecurityAction.Demand)]
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);

            // Get the location of regasm.
            string regasmPath       = RuntimeEnvironment.GetRuntimeDirectory() + @"regasm.exe";

            // Get the location of our DLL.
            string componentPath    = typeof(RegasmTlbInstaller).Assembly.Location;

            // Execute regasm.
            Process p               = new Process();
            p.StartInfo.FileName    = regasmPath;
            p.StartInfo.Arguments   = "\"" + componentPath + "\" /tlb /codebase";
            p.StartInfo.Verb        = "runas";          // To run as administrator.
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.Start();
            p.WaitForExit();
        }

        [SecurityPermission(SecurityAction.Demand)]
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        /// <summary>
        /// Runs regasm /u /tlb /codebase to un-register and delete the TLB file.
        /// </summary>
        [SecurityPermission(SecurityAction.Demand)]
        public override void Uninstall(IDictionary savedState)
        {
            // Get the location of regasm.
            string regasmPath       = RuntimeEnvironment.GetRuntimeDirectory() + @"regasm.exe";

            // Get the location of our DLL.
            string componentPath    = typeof(RegasmTlbInstaller).Assembly.Location;

            // Execute regasm.
            Process p               = new Process();

            p.StartInfo.FileName    = regasmPath;
            p.StartInfo.Arguments   = "/u \"" + componentPath + "\" /tlb /codebase";
            p.StartInfo.Verb        = "runas";          // To run as administrator.
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.Start();
            p.WaitForExit();

            // Delete the TLB file.
            File.Delete(Path.Combine(Path.GetDirectoryName(componentPath), Path.GetFileNameWithoutExtension(componentPath) + ".tlb"));

            base.Uninstall(savedState);
        }
    }
}

Since this class also implements Rollback and Uninstall overloads, we need to add Custom Action for Rollback and Uninstall in the installer project as well (as in steps 6 and 7 mentioned above).

Additionally, the installer project properties should typically set as follows:
  • Project properties:
    • DetectNewerInstallation: True
    • InstallAllUsers: True
    • RemovePreviousVersions: True
  • Primary Output properties:
    • Register: vsdrpCOM
    • SharedLegacy: True
    • (User's Desktop and User's Programs Menu leave empty)

Finally, after building the installer project, please make sure the TLB file generated (e.g. MyCom.COM.tlb) is excluded from the "Detected Dependencies" folder.


Additional Resources:
C# COM Interop And Events


If you find this post helpful, would you buy me a coffee?