Meet LockerMeet Locker is an application that allows users to securely store and retrieve data.
Press the Store button and you get the screen to enter the data and password:
Server API code for receiving text and password and returning key:
public class PutForm
{
public string? pwd { get; set; }
public string? filename { get; set; }
public string? text { get; set; }
}
[HttpPost("put")]
public async TaskServer (Mgr) backend code for processing text and password into key:
public static async Task<string?> Store(string pwd, string filename, Stream file)
{
string key = GetKey();
string? zip_file_path = GetFilePath(key, pwd);
if (zip_file_path == null)
return null;
using (Stream zip_file = File.Create(zip_file_path))
{
using (ZipOutputStream zip_file_stream = new ZipOutputStream(zip_file))
{
var entry = new ZipEntry(filename);
zip_file_stream.PutNextEntry(entry);
zip_file_stream.Password = pwd;
await file.CopyToAsync(zip_file_stream);
}
}
return key;
}
// Given key and password return where the file might be found
public static string? GetFilePath(string key, string pwd)
{
if (!IsKeyValid(key))
return null;
string total_key_pwd = Convert.ToHexString(Encoding.UTF8.GetBytes(key + pwd));
int chars_per = 16;
StringBuilder file_path_builder = new StringBuilder(total_key_pwd.Length * 2);
file_path_builder.Append(FilesDirPath);
file_path_builder.Append('/');
var view = total_key_pwd.AsSpan();
for (int x = 0; x < total_key_pwd.Length; x += chars_per)
{
file_path_builder.Append(view.Slice(start: x, length: Math.Min(total_key_pwd.Length - x, chars_per)));
file_path_builder.Append('/');
}
string file_path = file_path_builder.ToString();
Directory.CreateDirectory(file_path);
file_path += "file.dat";
return file_path;
}
// Key generation centralized to make a DemoKey for length validation
public static string GetKey()
{
// build the key to the castle with a GUID for uniqueness and randomness for difficulty in guess
byte[] guid_bytes = Guid.NewGuid().ToByteArray();
string key =
Convert.ToHexString(guid_bytes) +
Convert.ToHexString(RandomNumberGenerator.GetBytes(guid_bytes.Length));
return key;
}
public static string DemoKey = GetKey();
public static bool IsKeyValid(string key)
{
if (key.Length != DemoKey.Length)
return false;
if (key.Any(c => !char.IsAsciiLetterOrDigit(c)))
return false;
return true;
}You receive the key needed to get the data back:
Someone gets the key and password and presses the Retrieve button on the home page to enter them:
Server API code for receiving key and password and returning text:
public class GetForm
{
public string? key { get; set; }
public string? pwd { get; set; }
}
[HttpPost("get")]
public async Task<ActionResult> Get([FromForm] GetForm form)
{
FileRetrieveHandler handler = Stream (string filename) => {
return Response.Body;
};
if (!await Mgr.Retrieve(form.key ?? "", form.pwd ?? "", handler))
return BadRequest();
return new EmptyResult();
}Server (Mgr) backend code for processing key and password into text:
// Given key and password, call a handler with the filename (for setting HTTP Content-Disposition).
// The handler returns the Stream to write the file contents to.
public static async Task<bool> Retrieve(string key, string pwd, FileRetrieveHandler handler)
{
string file_path = GetFilePath(key, pwd);
if (!File.Exists(file_path))
return false;
using (Stream file_stream = File.OpenRead(file_path))
{
using (ZipFile zip_file = new ZipFile(file_stream))
{
zip_file.Password = pwd;
string filename = "";
foreach (ZipEntry entry in zip_file)
{
filename = entry.Name;
break;
}
if (string.IsNullOrWhiteSpace(filename))
throw new Exception("Filename not found");
using (var zip_stream = zip_file.GetInputStream(0))
{
var output_stream = handler(filename);
await zip_stream.CopyToAsync(output_stream);
output_stream.Dispose();
}
}
}
File.Delete(file_path);
return true;
}They receive the data:
The server deletes the locker, and the deed is done. NotesThis is a proof-of-concept demonstrating the code involved with doing something like this. The application is a self-contained portable ASP.NET Core Web API Kestrel program. The application is distributed via source code at GitHub. There is no "live" version of this application. It's a source code demonstration. I hope for derivative work that goes live with something along these lines. Send questions and comments to Michael Balloni michael@michaelballoni.com. Check out more of Michael's shenanigans at michaelballoni.com. Enjoy! Copyright © 2026 - Michael Balloni - All rights reserved. |