Thursday, May 29, 2025

Insights from Steve Jobs on Programming and Technology


1. Programming and Creativity

“Everybody in this country should learn how to program a computer because it teaches you how to think.”

— Steve Jobs

Jobs believed programming wasn’t just a technical skill but a fundamental way of thinking—one that fosters creativity and problem-solving.



2. Technology as a Tool for Art

“It’s in Apple’s DNA that technology alone is not enough. It’s technology married with liberal arts, married with the humanities, that yields us the results that make our hearts sing.”

— Steve Jobs

He saw programming and technology as mediums to create products with elegance, beauty, and human-centered design, not just functionality.


3. Simplicity in Software and Design

“Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it’s worth it in the end because once you get there, you can move mountains.”

— Steve Jobs

For Jobs, programming and software design should strive for simplicity and clarity to truly empower users.


4. The Power of Interactivity

“Design is not just what it looks like and feels like. Design is how it works.”

— Steve Jobs

In programming, this meant creating interfaces and systems that are intuitive and seamless — bridging human interaction with technology.


5. On Innovation and Programming

“Innovation distinguishes between a leader and a follower.”

— Steve Jobs

Programming, in Jobs’ view, was a core ingredient for innovation, enabling companies to lead rather than follow.


6. Programming as a Liberal Art

“I think everybody in this country should learn how to program a computer because it teaches you how to think.”

— Steve Jobs, 1995 interview

He advocated that computer science should be a fundamental part of education, similar to art or literature.


7. Focus on the User Experience

“Get closer than ever to your customers. So close that you tell them what they need before they realize it themselves.”

— Steve Jobs

In programming, this means anticipating user needs and creating software that delights.


8. On Software Quality

“Quality is more important than quantity. One home run is much better than two doubles.”

— Steve Jobs

He prioritized writing clean, powerful code that delivers impact over lots of mediocre features.

Wednesday, May 28, 2025

How to Use log4net for Logging in C# Applications

Logging is a crucial aspect of software development, helping you track issues, monitor behavior, and maintain applications more effectively. log4net is a powerful, flexible logging library for .NET applications, inspired by the Java-based log4j. This guide shows how to integrate log4net into a C# project with a working example.

Key Features of log4net

  • Easy to configure via XML or code.
  • Supports multiple logging targets (file, console, event log, etc.).
  • Thread-safe logging.
  • Fine-grained control over log levels: DEBUG, INFO, WARN, ERROR, FATAL.

Step-by-Step Guide:


1. Install log4net via NuGet

Open the NuGet Package Manager Console and run:

Install-Package log4net

2. Add Configuration in App.config or Web.config

Add the following inside your configuration file:

<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="Logs\\app.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="1MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingFileAppender" />
    </root>
  </log4net>
</configuration>
Note: Ensure the Logs folder exists or your application has permission to create/write to it.

3. Initialize and Use log4net in C# Code

Here’s a simple example in Program.cs:

using System;
using log4net;
using log4net.Config;
using System.Reflection;

class Program
{
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    static void Main(string[] args)
    {
        XmlConfigurator.Configure(); // Loads config from App.config
        log.Info("Application started");

        try
        {
            int a = 10, b = 0;
            int result = a / b;
        }
        catch (Exception ex)
        {
            log.Error("An error occurred", ex);
        }

        log.Warn("This is a warning");
        log.Debug("Debug message");
        log.Fatal("Fatal error simulation");

        Console.WriteLine("Done. Check the Logs folder.");
    }
}

Output Example

This configuration writes logs to Logs\app.log with entries like:

2025-05-28 10:35:14,553 [1] INFO  Program - Application started
2025-05-28 10:35:14,559 [1] ERROR Program - An error occurred
System.DivideByZeroException: Attempted to divide by zero.
   at Program.Main(String[] args)

How to Securing Passwords Against Quantum Computers

Why special care for passwords?

Passwords are stored as hashes, not encrypted, to prevent attackers from recovering the original password if the database leaks. However, with quantum computers, classical password hashing algorithms could become easier to brute force.

Quantum Threats to Password Hashing

  • Grover’s algorithm speeds up brute-force attacks quadratically on symmetric cryptography and hash functions.
  • This means attackers could try roughly the square root of password guesses in the same time compared to classical brute force.
  • Password hashing needs to be computationally expensive and memory-hard, making each guess costly on quantum hardware.

Best Practices for Quantum-Resistant Password Hashing

  1. Use slow, memory-hard hashing algorithms designed for password storage like Argon2, scrypt, or bcrypt.
  2. Always use a unique random salt per password.
  3. Use sufficiently large parameters (iterations, memory, CPU cost) to slow brute forcing.
  4. Use constant-time verification to avoid timing attacks.

C# Examples for Quantum-Resistant Password Hashing:


1. Argon2 — Recommended for quantum resistance

// Install NuGet Package: Install-Package Isopoh.Cryptography.Argon2
using Isopoh.Cryptography.Argon2;
using System;

class Program
{
    static void Main()
    {
        string password = "MyQuantumSafePassword123!";

        // Hash the password with Argon2id
        string hash = Argon2.Hash(password);

        Console.WriteLine($"Argon2 Hash: {hash}");

        // Verify the password
        bool valid = Argon2.Verify(hash, password);
        Console.WriteLine($"Password valid? {valid}");
    }
}

2. bcrypt — Widely used, moderately quantum-resistant

// Install NuGet Package: Install-Package BCrypt.Net-Next
using BCrypt.Net;

class Program
{
    static void Main()
    {
        string password = "MyQuantumSafePassword123!";

        // Generate bcrypt hash
        string hash = BCrypt.Net.BCrypt.HashPassword(password);

        Console.WriteLine($"bcrypt Hash: {hash}");

        // Verify the password
        bool valid = BCrypt.Net.BCrypt.Verify(password, hash);
        Console.WriteLine($"Password valid? {valid}");
    }
}

3. scrypt — Memory-hard, good for resisting quantum attacks

// Install NuGet Package: Install-Package CryptSharpOfficial
using CryptSharp;

class Program
{
    static void Main()
    {
        string password = "MyQuantumSafePassword123!";

        // Generate scrypt hash
        string hash = Crypter.Scrypt.Crypt(password);

        Console.WriteLine($"scrypt Hash: {hash}");

        // Verify the password
        bool valid = Crypter.CheckPassword(password, hash);
        Console.WriteLine($"Password valid? {valid}");
    }
}

4. PBKDF2 — Built-in, less memory-hard, but still usable with high iteration count

using System;
using System.Security.Cryptography;

class Program
{
    static void Main()
    {
        string password = "MyQuantumSafePassword123!";

        // Generate a 16-byte salt
        byte[] salt = new byte[16];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }

        // Derive a 256-bit key using PBKDF2 with 100,000 iterations and SHA256
        var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256);
        byte[] hash = pbkdf2.GetBytes(32);

        // Convert to base64 for storage
        string saltBase64 = Convert.ToBase64String(salt);
        string hashBase64 = Convert.ToBase64String(hash);

        Console.WriteLine($"Salt: {saltBase64}");
        Console.WriteLine($"Hash: {hashBase64}");

        // Verification
        var pbkdf2Verify = new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256);
        byte[] hashToVerify = pbkdf2Verify.GetBytes(32);

        bool valid = CryptographicOperations.FixedTimeEquals(hash, hashToVerify);
        Console.WriteLine($"Password valid? {valid}");
    }
}