How to Create a Local Secret Data Vault for .NET Applications: SQLiteCipher with Dapper

Using a Configuration File


You can also store secrets in a local configuration file and encrypt it.


Create a JSON file (e.g., appsettings.secret.json):

{
    "SecretKey": "YourSecretValue"
}


Also, Update appsetting.json

"ConnectionStrings": {
  "DefaultConnection": "localvault.db"
}


Load the Configuration at program.cs:

using LocalVaultWebApi.Data;
using Microsoft.Extensions.DependencyInjection;
using SQLitePCL;
using System;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

//Batteries_V2.Init(); // Initialize SQLitePCL (needed for SQLCipher)

// Load secrets file
var secretConfig = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.secret.json", optional: true)
    .Build();

var secretValue = secretConfig["SecretKey"];

builder.Services.AddSingleton<DapperContext>(provider =>
    new DapperContext(builder.Configuration, secretValue));

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll",
        builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
else
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseCors("AllowAll");

app.UseHttpsRedirection();

app.MapControllers();

app.Run();


Encrypt the Configuration: You may want to encrypt the sensitive values in this file to prevent unauthorized access.


Using a Local Database (SQLite with SQLiteCipher)


If you require a more complex solution, consider storing secrets in a local database.


Set Up SQLite: Install the SQLite package via NuGet:

dotnet add package Dapper
dotnet add package Microsoft.Data.Sqlite
dotnet add package SQLitePCLRaw.bundle_e_sqlcipher


Create a DapperContext.cs:

using Microsoft.Data.Sqlite;
using System.Data;
using System.Data.SQLite;

namespace LocalVaultWebApi.Data
{
    public class DapperContext
    {
        private readonly IConfiguration _configuration;
        private readonly string _connectionString;
        private readonly string _secretValue;
        public DapperContext(IConfiguration configuration, string secretValue)
        {
            _configuration = configuration;
            _secretValue = secretValue;
            _connectionString = _configuration.GetConnectionString("DefaultConnection");

            // Initialize SQLiteCipher (this can be done here or in a more central location)
            SQLitePCL.Batteries_V2.Init();  // This ensures SQLiteCipher is ready
        }

        public IDbConnection CreateConnection()
        {
            var connectionString = new SqliteConnectionStringBuilder
            {
                DataSource = _connectionString,  // Path to your SQLite database file
                Mode = SqliteOpenMode.ReadWriteCreate  // Allow reading and writing to the DB
            }.ToString();

            var connection = new SqliteConnection(connectionString);
            connection.Open();

            // Set the encryption key (PRAGMA key) after opening the connection
            using (var command = connection.CreateCommand())
            {
                command.CommandText = $"PRAGMA key = '{_secretValue}';";  // Set your encryption password
                command.ExecuteNonQuery();
            }

            return connection;  // Return the opened, encrypted connection ready for Dapper
        }
    }
}


Create Secret Class as a Model:

public class Secret
{
    public int Id { get; set; }
    public string Key { get; set; }
    public string Value { get; set; }
}

public class SecretRequest
{
    public string Key { get; set; }
    public string Value { get; set; }
}


Create a Controller to Access Secret Vualt


[Route("api/[controller]/[action]")]
[ApiController]
public class SecretController : ControllerBase
{
    private readonly DapperContext _dapperContext;

    public SecretController(DapperContext dapperContext)
    {
        _dapperContext = dapperContext;
    }

    [HttpGet]
    public IActionResult CreateDatabase()
    {
        var result = 0;

       using var connection = _dapperContext.CreateConnection();
       try
        {
            string sql2 = "CREATE TABLE IF NOT EXISTS Secret (Id INTEGER PRIMARY KEY, key TEXT,value TEXT)";

            connection.Execute(sql2);
        }
        catch (Exception ex) 
        { 
        
        }
        return Ok(true);
    }

    [HttpGet]
    public IActionResult GetSecret(string key)
    {
        var result =new Secret();


        using (var connection = _dapperContext.CreateConnection())
        {              

            string sql = "SELECT * From Secret Where key=@key";

            result = connection.QueryFirstOrDefault<Secret>(sql, new { key });
        }

        return Ok(result);
    }

    [HttpPost]
    public IActionResult StoreSecret(SecretRequest request_data)
    {
        var result = 0;

        using (var connection = _dapperContext.CreateConnection())
        {
            
            string sql = "INSERT INTO Secret(Key,Value) VALUES (@Key,@Value)";

            result =  connection.Execute(sql, new { request_data.Key, request_data.Value });
        }

        return Ok(result);
    }

}