Skip to content

split storage key and encryption key #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions Snappass.NET/Controllers/PasswordController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ public PasswordController(IMemoryStore memoryStore, ILogger<PasswordController>
}

[HttpGet]
[HttpPost]
public IActionResult Preview(string key)
{
if (!_memoryStore.Has(key))
(string storageKey, string encryptionKey) = Encryption.ParseToken(key);
if (!_memoryStore.Has(storageKey))
{
_logger.LogWarning($@"password with key {key} requested, but not found");
_logger.LogWarning($@"password with key {storageKey} requested, but not found");
return NotFound();
}
string encryptedPassword = _memoryStore.Retrieve(key);
string decrypted = Encryption.Decrypt(encryptedPassword, key);
return View("Preview", new PreviewModel { Key = decrypted });
if (HttpContext.Request.Method == "POST")
{
string encryptedPassword = _memoryStore.Retrieve(storageKey);
string decrypted = Encryption.Decrypt(encryptedPassword, encryptionKey);
return View("Password", new PreviewModel { Key = decrypted });
}

return View("Preview");
}
}
}
11 changes: 7 additions & 4 deletions Snappass.NET/Controllers/ShareController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@ public IActionResult Share(string password, string ttl)
"week" => TimeToLive.Week,
"day" => TimeToLive.Day,
"hour" => TimeToLive.Hour,
_ => throw new ArgumentException("Expected week, day or hour"),
"twoweeks" => TimeToLive.TwoWeeks,
_ => throw new ArgumentException("Expected twoweeks, week, day or hour"),
};
TimeToLive timeToLive = Parse(ttl);
(string encryptedPassword, string key) = Encryption.Encrypt(password);
_memoryStore.Store(encryptedPassword, key, timeToLive);
var model = new GeneratedPassword { Key = key, BaseUri = GetBaseUrl() };
string storageKey = Guid.NewGuid().ToString("N").ToUpper();
(string encryptedPassword, string encryptionKey) = Encryption.Encrypt(password);
_memoryStore.Store(encryptedPassword, storageKey, timeToLive);
string token = Encryption.CreateToken(storageKey, encryptionKey);
var model = new GeneratedPassword { Token = token, BaseUri = GetBaseUrl() };
return View("Shared", model);
}
}
Expand Down
38 changes: 30 additions & 8 deletions Snappass.NET/Encryption.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
using System;
using System.Net;
using Fernet;

namespace Snappass
{
public class Encryption
{
public static (string encryptedPassword, string key) Encrypt(string password)
private static readonly char tokenSeparator = '~';

public static (string encryptedPassword, string encryptionKey) Encrypt(string password)
{
byte[] keyBytes = SimpleFernet.GenerateKey().UrlSafe64Decode();
byte[] EncryptionKeyBytes = SimpleFernet.GenerateKey().UrlSafe64Decode();
var passwordBytes = System.Text.Encoding.Unicode.GetBytes(password);
string encrypted = SimpleFernet.Encrypt(keyBytes, passwordBytes);
string key = keyBytes.UrlSafe64Encode();
return (encrypted, key);
string encryptedPassword = SimpleFernet.Encrypt(EncryptionKeyBytes, passwordBytes);
string encryptionKey = EncryptionKeyBytes.UrlSafe64Encode();
return (encryptedPassword, encryptionKey);
}

public static string Decrypt(string encrypted, string key)
public static string Decrypt(string encryptedPassword, string encryptionKey)
{
var keyBytes = key.UrlSafe64Decode();
var decryptedBytes = SimpleFernet.Decrypt(keyBytes, encrypted, out DateTime _);
var encryptionKeyBytes = encryptionKey.UrlSafe64Decode();
var decryptedBytes = SimpleFernet.Decrypt(encryptionKeyBytes, encryptedPassword, out DateTime _);
var decrypted = decryptedBytes.UrlSafe64Encode().FromBase64String().Replace("\0", "");
return decrypted;
}

public static (string storageKey, string decryptionKey) ParseToken(string token)
{
var tokenFragments = token.Split(tokenSeparator, 2);
var storageKey = tokenFragments[0];
var decryptionKey = string.Empty;

if (tokenFragments.Length > 1)
decryptionKey = WebUtility.UrlDecode(tokenFragments[1]);

return (storageKey, decryptionKey);
}
public static string CreateToken(string storageKey, string encryptionKey)
{
var token = string.Join(tokenSeparator, storageKey, WebUtility.UrlEncode(encryptionKey));

return token;

}
}
}
12 changes: 8 additions & 4 deletions Snappass.NET/MemoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,22 @@ public string Retrieve(string key)
TimeToLive.Day => item.StoredDateTime.AddDays(1),
TimeToLive.Week => item.StoredDateTime.AddDays(7),
TimeToLive.Hour => item.StoredDateTime.AddHours(1),
TimeToLive.TwoWeeks => item.StoredDateTime.AddDays(14),
_ => item.StoredDateTime.AddHours(1),
};
DateTime atTheLatest = GetAtTheLatest(item.TimeToLive);
if (_dateTimeProvider.Now > atTheLatest)
{
static string ToString(TimeToLive ttl) => ttl switch
{
TimeToLive.Week => "week",
TimeToLive.Day => "day",
TimeToLive.Hour => "hour",
TimeToLive.Week => "1 week",
TimeToLive.Day => "1 day",
TimeToLive.Hour => "1 hour",
TimeToLive.TwoWeeks => "2 weeks",
_ => "1 hour",
};
var ttlString = ToString(item.TimeToLive);
_logger.Log(LogLevel.Warning, $@"Tried to retrieve password for key [{key}] after date is expired. Key set at [{item.StoredDateTime}] for 1 [{ttlString}]");
_logger.Log(LogLevel.Warning, $@"Tried to retrieve password for key [{key}] after date is expired. Key set at [{item.StoredDateTime}] for [{ttlString}]");
_items.Remove(key); // ensure "read-once" is implemented
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions Snappass.NET/Models/GeneratedPassword.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
{
public class GeneratedPassword
{
public string Key { get; set; }
public string Token { get; set; }
public string BaseUri { get; set; }
public string Uri => $@"{BaseUri}/Password/{Key}";
public string Uri => $@"{BaseUri}/Password/{Token}";
}
}
11 changes: 7 additions & 4 deletions Snappass.NET/SqliteStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public override TimeToLive Parse(object value)
0 => TimeToLive.Hour,
1 => TimeToLive.Day,
2 => TimeToLive.Week,
3 => TimeToLive.TwoWeeks,
_ => TimeToLive.Hour,
};
}
Expand Down Expand Up @@ -103,20 +104,22 @@ FROM SECRET
TimeToLive.Day => dateTime.AddDays(1),
TimeToLive.Week => dateTime.AddDays(7),
TimeToLive.Hour => dateTime.AddHours(1),
TimeToLive.TwoWeeks => dateTime.AddDays(14),
_ => dateTime.AddHours(1)
};
DateTime atTheLatest = GetAtTheLatest(secret.TimeToLive, secret.StoredDateTime);
if (_dateTimeProvider.Now > atTheLatest)
{
static string ToString(TimeToLive ttl) => ttl switch
{
TimeToLive.Week => "week",
TimeToLive.Day => "day",
TimeToLive.Hour => "hour",
TimeToLive.Week => "1 week",
TimeToLive.Day => "1 day",
TimeToLive.Hour => "1 hour",
TimeToLive.TwoWeeks => "2 weeks",
_ => "hour"
};
var ttlString = ToString(secret.TimeToLive);
_logger.Log(LogLevel.Warning, $@"Tried to retrieve password for key [{key}] after date is expired. Key set at [{secret.StoredDateTime}] for 1 [{ttlString}]");
_logger.Log(LogLevel.Warning, $@"Tried to retrieve password for key [{key}] after date is expired. Key set at [{secret.StoredDateTime}] for [{ttlString}]");
Remove(key);
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion Snappass.NET/TimeToLive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{
public enum TimeToLive
{
Week, Day, Hour
Week, Day, Hour, TwoWeeks
}
}
25 changes: 25 additions & 0 deletions Snappass.NET/Views/Password/Password.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@{
ViewData["Title"] = "ViewPassword";
Layout = "~/Views/_Layout.cshtml";
}
<div class="container">
<section>
<div class="page-header"><h1>Secret</h1></div>
<p>Save the following secret to a secure location.</p>
<div class="row">
<div class="col-sm-6 margin-bottom-10">
<textarea class="form-control" rows="10" cols="50" id="password-text" name="password-text" readonly="readonly">@Model.Key</textarea>
</div>

<div class="col-sm-6">
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-text"
data-placement='bottom'>
<i class="fa fa-clipboard"></i>
</button>
</div>
</div>
<p>The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.</p>
</section>
</div>
<script src="~/js/clipboard_button.js"></script>
16 changes: 2 additions & 14 deletions Snappass.NET/Views/Password/Preview.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@{
ViewData["Title"] = "ViewPassword";
ViewData["Title"] = "PreviewPassword";
Layout = "~/Views/_Layout.cshtml";
}
<div class="container">
Expand All @@ -14,18 +14,6 @@
</div>
</div>
</section>
<section id="revealed">
<p>Save the following secret to a secure location.</p>
<div class="input-group">
<textarea class="form-control" rows="10" cols="50" id="password-text" name="password-text" readonly="readonly">@Model.Key</textarea>
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-text"
data-placement='bottom'>
<i class="fa fa-clipboard"></i>
</button>
</div>
<p>The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.</p>
</section>
</div>
<script src="~/js/preview.js"></script>
<script src="~/js/clipboard_button.js"></script>

3 changes: 2 additions & 1 deletion Snappass.NET/Views/Share/Share.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

<div class="margin-bottom-10">
<select class="form-control" name="ttl">
<option value="TwoWeeks">Two Weeks</option>
<option value="Week">Week</option>
<option value="Day">Day</option>
<option value="Hour">Hour</option>
<option value="Hour" selected>Hour</option>
</select>
</div>

Expand Down
7 changes: 5 additions & 2 deletions Snappass.NET/wwwroot/js/preview.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
(function () {
$('#revealSecret').click(function (e) {
$('#revealed').show();
$('#revealSecret').prop("disabled", true);
var form = $('<form/>')
.attr('id', 'revealSecretForm')
.attr('method', 'post');
form.appendTo($('body'));
form.submit();
});
})();