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); } }