initial commit

This commit is contained in:
WeeXnes 2025-05-06 02:18:04 +02:00
commit 9961b7792c
15 changed files with 548 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

16
Cryptura.sln Normal file
View file

@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cryptura", "Cryptura\Cryptura.csproj", "{7C536079-3ADF-4E9B-9A0F-DC0DC743DF60}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7C536079-3ADF-4E9B-9A0F-DC0DC743DF60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C536079-3ADF-4E9B-9A0F-DC0DC743DF60}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C536079-3ADF-4E9B-9A0F-DC0DC743DF60}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C536079-3ADF-4E9B-9A0F-DC0DC743DF60}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

10
Cryptura/App.axaml Normal file
View file

@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Cryptura.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

23
Cryptura/App.axaml.cs Normal file
View file

@ -0,0 +1,23 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace Cryptura;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
}
base.OnFrameworkInitializationCompleted();
}
}

20
Cryptura/Core.cs Normal file
View file

@ -0,0 +1,20 @@
using System;
using System.IO;
using Avalonia.Controls;
namespace Cryptura;
public class Core
{
public static bool IsRunningOnGnome()
{
var xdgDesktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
return xdgDesktop != null && xdgDesktop.Contains("GNOME", StringComparison.OrdinalIgnoreCase);
}
public static void SetClipboardText(string text, Window window)
{
window.Clipboard?.SetTextAsync(text);
}
}

22
Cryptura/Cryptura.csproj Normal file
View file

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.7"/>
<PackageReference Include="Avalonia.Desktop" Version="11.2.7"/>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.7"/>
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.7"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.7">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,64 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Cryptura;
public static class EncryptionLibrary
{
private const int SaltSize = 16;
private const int KeySize = 32;
private const int Iterations = 10000;
public static string Encrypt(string masterPassword, string plainPassword)
{
byte[] salt = new byte[SaltSize];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
}
using (var aesAlg = Aes.Create())
{
var key = new Rfc2898DeriveBytes(masterPassword, salt, Iterations);
aesAlg.Key = key.GetBytes(KeySize);
aesAlg.IV = new byte[16];
using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (var ms = new MemoryStream())
{
ms.Write(salt, 0, salt.Length);
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
using (var writer = new StreamWriter(cs))
{
writer.Write(plainPassword);
}
return Convert.ToBase64String(ms.ToArray());
}
}
}
public static string Decrypt(string masterPassword, string encryptedPassword)
{
byte[] cipherBytes = Convert.FromBase64String(encryptedPassword);
byte[] salt = new byte[SaltSize];
Array.Copy(cipherBytes, 0, salt, 0, SaltSize); // Extract the salt
using (var aesAlg = Aes.Create())
{
var key = new Rfc2898DeriveBytes(masterPassword, salt, Iterations);
aesAlg.Key = key.GetBytes(KeySize);
aesAlg.IV = new byte[16];
using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (var ms = new MemoryStream(cipherBytes, SaltSize, cipherBytes.Length - SaltSize))
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (var reader = new StreamReader(cs))
{
return reader.ReadToEnd();
}
}
}
}

21
Cryptura/Globals.cs Normal file
View file

@ -0,0 +1,21 @@
using System;
using System.IO;
using Microsoft.VisualBasic.CompilerServices;
namespace Cryptura;
public class Globals
{
public static string GetKeyDirectory()
{
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string keyDirectory = Path.Combine(homeDir, ".cryptura");
Util.CheckDir(keyDirectory);
return keyDirectory;
}
public static string GenerateUuidFilename()
{
return Guid.NewGuid() + ".wx";
}
}

56
Cryptura/MainWindow.axaml Normal file
View file

@ -0,0 +1,56 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Cryptura"
mc:Ignorable="d"
x:Class="Cryptura.MainWindow"
TransparencyLevelHint="AcrylicBlur"
Background="Transparent"
Height="400"
Width="520"
WindowStartupLocation="CenterScreen"
Title="Cryptura">
<!--ExtendClientAreaToDecorationsHint="True"-->
<Panel>
<ExperimentalAcrylicBorder IsHitTestVisible="False" Name="AcrylicBorderObject">
<ExperimentalAcrylicBorder.Material>
<ExperimentalAcrylicMaterial
BackgroundSource="Digger"
TintColor="Black"
TintOpacity="1"
MaterialOpacity="0.65"/>
</ExperimentalAcrylicBorder.Material>
</ExperimentalAcrylicBorder>
<Grid RowDefinitions="4*, 50">
<Border Grid.Row="0" Background="#35313d" CornerRadius="10" Margin="10">
<ListBox Name="PasswordList" Background="Transparent" SelectionChanged="PasswordList_OnSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="local:Password">
<Border Background="Transparent" Padding="10">
<Grid ColumnDefinitions="*, *">
<TextBlock Grid.Column="0" Foreground="White" Text="{Binding Name}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Foreground="White" Text="{Binding DisplayValue}" VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Styles>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="#35313d"/>
</Style>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="CornerRadius" Value="10"/>
</Style>
</ListBox.Styles>
</ListBox>
</Border>
<Border Grid.Row="1" Background="#35313d" CornerRadius="10" Margin="10,0,10,10">
<Button Click="Button_OnClick"></Button>
</Border>
</Grid>
</Panel>
</Window>

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace Cryptura;
public partial class MainWindow : Window
{
public static bool censorPasswords = true;
private void AdjustThemeToPlatform()
{
if (Core.IsRunningOnGnome())
{
this.TransparencyLevelHint = new[] { WindowTransparencyLevel.None };
this.Background = new SolidColorBrush(Color.Parse("#201c29"));
AcrylicBorderObject.IsVisible = false;
}
else
{
this.TransparencyLevelHint = new[] { WindowTransparencyLevel.AcrylicBlur };
this.Background = Brushes.Transparent;
AcrylicBorderObject.IsVisible = true;
}
}
public MainWindow()
{
InitializeComponent();
AdjustThemeToPlatform();
FetchPasswords();
Password pw = new Password("monkeyman", "Himself");
}
private void FetchPasswords(){
List<Password> passwords = new List<Password>();
string[] WXFiles = Directory.GetFiles(Globals.GetKeyDirectory());
foreach (string file in WXFiles)
{
if (Path.GetExtension(file).ToLower() == ".kf")
{
Password pw = new Password(file);
pw.WxFile.Verify();
}
else
{
Console.WriteLine("Skipped non-key file: " + file);
}
}
PasswordList.ItemsSource = passwords;
}
private void Control_OnLoaded(object? sender, RoutedEventArgs e)
{
if (sender is TextBox textBox)
{
Console.WriteLine("called");
textBox.Bind(TextBlock.TextProperty, new Binding("Value"));
}
}
private void Button_OnClick(object? sender, RoutedEventArgs e)
{
censorPasswords = !censorPasswords;
FetchPasswords();
}
private void PasswordList_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (PasswordList.SelectedItem is Password password) Core.SetClipboardText(password.Value, this);
}
}

36
Cryptura/Password.cs Normal file
View file

@ -0,0 +1,36 @@
using System;
using System.IO;
using System.Net;
using Avalonia.Data.Core;
namespace Cryptura;
public class Password
{
public string Name { get; set; }
public string Value { get; set; }
public string CensoredValue { get; set; } = "******";
public WXFile WxFile { get; set; }
public string DisplayValue
{
get => MainWindow.censorPasswords ? Value : CensoredValue;
}
public Password(string name, string value)
{
this.Name = name;
this.Value = value;
this.WxFile = new WXFile(Path.Combine(Globals.GetKeyDirectory(), Globals.GenerateUuidFilename()));
this.WxFile.WriteHeader();
this.WxFile.SetName(this.Name);
this.WxFile.SetValue(this.Value);
}
public Password(string filepath)
{
}
}

21
Cryptura/Program.cs Normal file
View file

@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace Cryptura;
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}

41
Cryptura/Util.cs Normal file
View file

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
namespace Cryptura;
public static class Util
{
public static string? OpenFileDialogSync(Window parent)
{
var dialog = new OpenFileDialog
{
Title = "Select PS2 ISO",
AllowMultiple = false,
Filters = new List<FileDialogFilter>
{
new FileDialogFilter { Name = "PS2 ISO", Extensions = { "iso", "bin" } },
new FileDialogFilter { Name = "All Files", Extensions = { "*" } }
}
};
var result = dialog.ShowAsync(parent).GetAwaiter().GetResult();
return result?.FirstOrDefault();
}
public static void CheckDir(string path)
{
if (!Directory.Exists(path))
{
Console.WriteLine("Directory " + path + " wasn't found, creating now.");
Directory.CreateDirectory(path);
}
else
{
Console.WriteLine("Directory was found: " + path);
}
}
}

120
Cryptura/WXFile.cs Normal file
View file

@ -0,0 +1,120 @@
using System;
using System.IO;
namespace Cryptura
{
public class WXFile
{
public string Path { get; set; }
public WXFile(string path)
{
this.Path = path;
}
public bool Verify()
{
try
{
var lines = File.ReadAllLines(this.Path);
if (lines.Length < 3)
return false;
if (lines[0] != "##WXFile##")
return false;
if (string.IsNullOrWhiteSpace(lines[1]) || string.IsNullOrWhiteSpace(lines[2]))
return false;
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Error reading file: {ex.Message}");
return false;
}
}
public string GetName()
{
try
{
var lines = File.ReadAllLines(this.Path);
return lines.Length >= 2 ? lines[1] : "";
}
catch
{
return "";
}
}
public void SetName(string value)
{
try
{
var lines = File.ReadAllLines(this.Path);
if (lines.Length < 3)
Array.Resize(ref lines, 3);
lines[1] = value;
File.WriteAllLines(this.Path, lines);
}
catch (Exception ex)
{
Console.WriteLine($"Error writing name: {ex.Message}");
}
}
public string GetValue()
{
try
{
var lines = File.ReadAllLines(this.Path);
return lines.Length >= 3 ? lines[2] : "";
}
catch
{
return "";
}
}
public void SetValue(string value)
{
try
{
var lines = File.ReadAllLines(this.Path);
if (lines.Length < 3)
Array.Resize(ref lines, 3);
lines[2] = value;
File.WriteAllLines(this.Path, lines);
}
catch (Exception ex)
{
Console.WriteLine($"Error writing value: {ex.Message}");
}
}
public void WriteHeader()
{
try
{
var lines = File.Exists(this.Path) ? File.ReadAllLines(this.Path) : new string[0];
if (lines.Length < 1)
Array.Resize(ref lines, 1);
lines[0] = "##WXFile##";
File.WriteAllLines(this.Path, lines);
}
catch (Exception ex)
{
Console.WriteLine($"Error writing header: {ex.Message}");
}
}
}
}

18
Cryptura/app.manifest Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="Cryptura.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>