- Added helper to edit/remove two factor secrets to/from Git. - Removed uneccessary references. - Added initial Unit Tests.master
@@ -26,6 +26,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Configuration", "Utilities\ | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikStreaming", "TeknikStreaming\TeknikStreaming.csproj", "{7695CE9A-A0DB-4D73-BC9B-2206481F0254}" | |||
EndProject | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FAC9FE6E-9AA9-45AD-AA72-40DDF7DC44C6}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtilitiesTests", "UtilitiesTests\UtilitiesTests.csproj", "{88DEB506-3F7E-4B39-8264-861976DC7434}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikTests", "TeknikTests\TeknikTests.csproj", "{9D7A805E-2629-476E-B36A-040AD332C7DC}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
@@ -91,11 +97,29 @@ Global | |||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.ActiveCfg = Release|Any CPU | |||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.Build.0 = Release|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Debug|x64.ActiveCfg = Debug|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Debug|x64.Build.0 = Debug|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Release|x64.ActiveCfg = Release|Any CPU | |||
{88DEB506-3F7E-4B39-8264-861976DC7434}.Release|x64.Build.0 = Release|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Debug|x64.ActiveCfg = Debug|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Debug|x64.Build.0 = Debug|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Release|x64.ActiveCfg = Release|Any CPU | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC}.Release|x64.Build.0 = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
EndGlobalSection | |||
GlobalSection(NestedProjects) = preSolution | |||
{E08975F9-1B84-41B0-875A-CEC9778C4F9E} = {783361EC-DCD6-4A34-8479-5476DF752C34} | |||
{88DEB506-3F7E-4B39-8264-861976DC7434} = {FAC9FE6E-9AA9-45AD-AA72-40DDF7DC44C6} | |||
{9D7A805E-2629-476E-B36A-040AD332C7DC} = {FAC9FE6E-9AA9-45AD-AA72-40DDF7DC44C6} | |||
EndGlobalSection | |||
EndGlobal |
@@ -19,7 +19,6 @@ using Teknik.Utilities; | |||
using Teknik.Models; | |||
using Teknik.Attributes; | |||
using System.Text; | |||
using Org.BouncyCastle.Crypto; | |||
using Teknik.Utilities.Cryptography; | |||
namespace Teknik.Areas.Upload.Controllers |
@@ -7,7 +7,6 @@ using Teknik.Configuration; | |||
using Teknik.Models; | |||
using Teknik.Utilities; | |||
using System.Text; | |||
using Org.BouncyCastle.Utilities.Encoders; | |||
using Teknik.Utilities.Cryptography; | |||
namespace Teknik.Areas.Upload |
@@ -452,11 +452,23 @@ namespace Teknik.Areas.Users.Controllers | |||
{ | |||
// They just enabled it, let's regen the key | |||
newKey = Authenticator.GenerateKey(); | |||
// New key, so let's upsert their key into git | |||
if (Config.GitConfig.Enabled) | |||
{ | |||
UserHelper.CreateUserGitTwoFactor(Config, user.Username, newKey, DateTimeHelper.GetUnixTimestamp()); | |||
} | |||
} | |||
else if (!twoFactorEnabled) | |||
{ | |||
// remove the key when it's disabled | |||
newKey = string.Empty; | |||
// Removed the key, so delete it from git as well | |||
if (Config.GitConfig.Enabled) | |||
{ | |||
UserHelper.DeleteUserGitTwoFactor(Config, user.Username); | |||
} | |||
} | |||
else | |||
{ |
@@ -6,6 +6,7 @@ using System.Linq; | |||
using System.Net; | |||
using System.Net.Mail; | |||
using System.Runtime.InteropServices; | |||
using System.Security.Cryptography; | |||
using System.Text; | |||
using System.Text.RegularExpressions; | |||
using System.Threading.Tasks; | |||
@@ -18,6 +19,9 @@ using Teknik.Configuration; | |||
using Teknik.Utilities; | |||
using Teknik.Models; | |||
using Teknik.Utilities.Cryptography; | |||
using MD5 = Teknik.Utilities.Cryptography.MD5; | |||
using SHA256 = Teknik.Utilities.Cryptography.SHA256; | |||
using SHA384 = Teknik.Utilities.Cryptography.SHA384; | |||
namespace Teknik.Areas.Users.Utility | |||
{ | |||
@@ -971,6 +975,12 @@ If you recieved this email and you did not reset your password, you can ignore t | |||
if (config.GitConfig.Enabled) | |||
{ | |||
// Git user exists? | |||
if (UserGitExists(config, username)) | |||
{ | |||
throw new Exception($"Git User '{username}' does not exist."); | |||
} | |||
string email = GetUserEmailAddress(config, username); | |||
// We need to check the actual git database | |||
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database.Server, config.GitConfig.Database.Database, config.GitConfig.Database.Username, config.GitConfig.Database.Password, config.GitConfig.Database.Port); | |||
@@ -1030,10 +1040,16 @@ If you recieved this email and you did not reset your password, you can ignore t | |||
// If Git is enabled | |||
if (config.GitConfig.Enabled) | |||
{ | |||
// Git user exists? | |||
if (UserGitExists(config, username)) | |||
{ | |||
throw new Exception($"Git User '{username}' does not exist."); | |||
} | |||
string email = GetUserEmailAddress(config, username); | |||
using (var client = new WebClient()) | |||
{ | |||
var obj = new { source_id = config.GitConfig.SourceId, email = email, login_name = email, password = password }; | |||
var obj = new {source_id = config.GitConfig.SourceId, email = email, login_name = email, password = password}; | |||
string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj); | |||
client.Headers[HttpRequestHeader.ContentType] = "application/json"; | |||
Uri baseUri = new Uri(config.GitConfig.Host); | |||
@@ -1048,6 +1064,102 @@ If you recieved this email and you did not reset your password, you can ignore t | |||
} | |||
} | |||
public static void CreateUserGitTwoFactor(Config config, string username, string secret, int unixTime) | |||
{ | |||
try | |||
{ | |||
// If Git is enabled | |||
if (config.GitConfig.Enabled) | |||
{ | |||
// Git user exists? | |||
if (UserGitExists(config, username)) | |||
{ | |||
throw new Exception($"Git User '{username}' does not exist."); | |||
} | |||
// Generate the scratch token | |||
string token = StringHelper.RandomString(8); | |||
// Get the Encryption Key from the git secret key | |||
byte[] keyBytes = MD5.Hash(Encoding.UTF8.GetBytes(config.GitConfig.SecretKey)); | |||
// Modify the input secret | |||
byte[] secBytes = Encoding.UTF8.GetBytes(secret); | |||
// Generate the encrypted secret using AES CGM | |||
byte[] encValue = Aes128CFB.Encrypt(secBytes, keyBytes); | |||
string finalSecret = Convert.ToBase64String(encValue); | |||
// Create connection to the DB | |||
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database.Server, config.GitConfig.Database.Database, config.GitConfig.Database.Username, config.GitConfig.Database.Password, config.GitConfig.Database.Port); | |||
// Get the user's UID | |||
string email = GetUserEmailAddress(config, username); | |||
string userSelect = @"SELECT id FROM gogs.user WHERE gogs.user.login_name = {0}"; | |||
var uid = mySQL.ScalarQuery(userSelect, new object[] { email }); | |||
// See if they have Two Factor already | |||
string sqlSelect = @"SELECT id | |||
FROM gogs.two_factor | |||
LEFT JOIN gogs.user ON gogs.user.id = gogs.gogs.two_factor.uid | |||
WHERE gogs.user.login_name = {0}"; | |||
var result = mySQL.ScalarQuery(sqlSelect, new object[] { email }); | |||
if (result != null) | |||
{ | |||
// They have an entry! Let's update it | |||
string insert = @"UPDATE gogs.two_factor SET uid = {1}, secret = {2}, scratch_token = {3}, updated_unix = {4} WHERE gogs.two_factor.id = {0}"; | |||
mySQL.Execute(insert, new object[] { result, uid, finalSecret, token, unixTime }); | |||
} | |||
else | |||
{ | |||
// They need a new entry | |||
string update = @"INSERT INTO gogs.two_factor SET (uid, secret, scratch_token, created_unix, updated_unix) VALUES ({0}, {1}, {2}, {3}, {4})"; | |||
mySQL.Execute(update, new object[] { uid, finalSecret, token, unixTime, 0 }); | |||
} | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
throw new Exception("Unable to edit git account two factor.", ex); | |||
} | |||
} | |||
public static void DeleteUserGitTwoFactor(Config config, string username) | |||
{ | |||
try | |||
{ | |||
// If Git is enabled | |||
if (config.GitConfig.Enabled) | |||
{ | |||
// Git user exists? | |||
if (UserGitExists(config, username)) | |||
{ | |||
throw new Exception($"Git User '{username}' does not exist."); | |||
} | |||
// Create connection to the DB | |||
MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database.Server, config.GitConfig.Database.Database, config.GitConfig.Database.Username, config.GitConfig.Database.Password, config.GitConfig.Database.Port); | |||
// Get the user's UID | |||
string email = GetUserEmailAddress(config, username); | |||
// See if they have Two Factor already | |||
string deleteSql = @"DELETE tf.* | |||
FROM gogs.two_factor tf | |||
LEFT JOIN gogs.user u ON u.id = tf.uid | |||
WHERE u.login_name = {0}"; | |||
mySQL.Execute(deleteSql, new object[] { email }); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
throw new Exception("Unable to delete git account two factor.", ex); | |||
} | |||
} | |||
public static void DeleteUserGit(Config config, string username) | |||
{ | |||
try | |||
@@ -1055,6 +1167,12 @@ If you recieved this email and you did not reset your password, you can ignore t | |||
// If Git is enabled | |||
if (config.GitConfig.Enabled) | |||
{ | |||
// Git user exists? | |||
if (UserGitExists(config, username)) | |||
{ | |||
throw new Exception($"Git User '{username}' does not exist."); | |||
} | |||
try | |||
{ | |||
Uri baseUri = new Uri(config.GitConfig.Host); |
@@ -51,10 +51,6 @@ | |||
<HintPath>..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="BouncyCastle.Crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942"> | |||
<HintPath>..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll</HintPath> | |||
<Private>True</Private> |
@@ -4,7 +4,6 @@ | |||
<package id="bootstrap" version="3.3.7" targetFramework="net452" userInstalled="true" /> | |||
<package id="Bootstrap.Flat" version="3.3.4" targetFramework="net452" /> | |||
<package id="Bootstrap.Switch" version="3.3.2.1" targetFramework="net452" /> | |||
<package id="BouncyCastle" version="1.8.1" targetFramework="net452" /> | |||
<package id="EntityFramework" version="6.1.3" targetFramework="net452" userInstalled="true" /> | |||
<package id="FontAwesome" version="4.7.0" targetFramework="net462" userInstalled="true" /> | |||
<package id="GitVersionTask" version="3.6.5" targetFramework="net462" developmentDependency="true" /> |
@@ -0,0 +1,36 @@ | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
// General Information about an assembly is controlled through the following | |||
// set of attributes. Change these attribute values to modify the information | |||
// associated with an assembly. | |||
[assembly: AssemblyTitle("TeknikTests")] | |||
[assembly: AssemblyDescription("")] | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("")] | |||
[assembly: AssemblyProduct("Teknik")] | |||
[assembly: AssemblyCopyright("Copyright © 2017")] | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
// Setting ComVisible to false makes the types in this assembly not visible | |||
// to COM components. If you need to access a type in this assembly from | |||
// COM, set the ComVisible attribute to true on that type. | |||
[assembly: ComVisible(false)] | |||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||
[assembly: Guid("9d7a805e-2629-476e-b36a-040ad332c7dc")] | |||
// Version information for an assembly consists of the following four values: | |||
// | |||
// Major Version | |||
// Minor Version | |||
// Build Number | |||
// Revision | |||
// | |||
// You can specify all the values or you can default the Build and Revision Numbers | |||
// by using the '*' as shown below: | |||
// [assembly: AssemblyVersion("1.0.*")] | |||
[assembly: AssemblyVersion("1.0.0.0")] | |||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -0,0 +1,83 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Import Project="..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" /> | |||
<Import Project="..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props" Condition="Exists('..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props')" /> | |||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||
<ProjectGuid>{9D7A805E-2629-476E-B36A-040AD332C7DC}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Teknik.Tests.TeknikTests</RootNamespace> | |||
<AssemblyName>TeknikTests</AssemblyName> | |||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion> | |||
<FileAlignment>512</FileAlignment> | |||
<NuGetPackageImportStamp> | |||
</NuGetPackageImportStamp> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Net.Http" /> | |||
<Reference Include="System.Xml" /> | |||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.assert, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.core, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.execution.desktop, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> | |||
<PropertyGroup> | |||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> | |||
</PropertyGroup> | |||
<Error Condition="!Exists('..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props'))" /> | |||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props'))" /> | |||
</Target> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
<Target Name="BeforeBuild"> | |||
</Target> | |||
<Target Name="AfterBuild"> | |||
</Target> | |||
--> | |||
</Project> |
@@ -0,0 +1,12 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="xunit" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net462" /> | |||
<package id="xunit.assert" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.core" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.extensibility.core" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.extensibility.execution" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.runner.console" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
<package id="xunit.runner.msbuild" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
<package id="xunit.runner.visualstudio" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
</packages> |
@@ -14,6 +14,8 @@ namespace Teknik.Configuration | |||
public string AccessToken { get; set; } | |||
public string SecretKey { get; set; } | |||
public int SourceId { get; set; } | |||
public DatabaseConfig Database { get; set; } | |||
@@ -23,6 +25,7 @@ namespace Teknik.Configuration | |||
Enabled = true; | |||
Host = string.Empty; | |||
AccessToken = string.Empty; | |||
SecretKey = string.Empty; | |||
SourceId = 1; | |||
Database = new DatabaseConfig(); | |||
} |
@@ -0,0 +1,74 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Security.Cryptography; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Teknik.Utilities.Cryptography | |||
{ | |||
public static class AES | |||
{ | |||
public static byte[] Encrypt(byte[] value, byte[] key, byte[] iv, int keyLength, int blockLength, int feedbackSize, CipherMode mode, PaddingMode paddingMode) | |||
{ | |||
using (var cipher = CreateCipher(key, iv, keyLength, blockLength, feedbackSize, mode, paddingMode)) | |||
{ | |||
return Encrypt(cipher, value); | |||
} | |||
} | |||
public static byte[] Decrypt(byte[] value, byte[] key, byte[] iv, int keyLength, int blockLength, int feedbackSize, CipherMode mode, PaddingMode paddingMode) | |||
{ | |||
using (var cipher = CreateCipher(key, iv, keyLength, blockLength, feedbackSize, mode, paddingMode)) | |||
{ | |||
return Decrypt(cipher, value); | |||
} | |||
} | |||
public static byte[] Encrypt(RijndaelManaged cipher, byte[] value) | |||
{ | |||
byte[] encryptedBytes; | |||
using (var encryptor = cipher.CreateEncryptor()) | |||
using (MemoryStream ms = new MemoryStream()) | |||
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) | |||
using (var bw = new BinaryWriter(cs, Encoding.UTF8)) | |||
{ | |||
bw.Write(value); | |||
bw.Close(); | |||
encryptedBytes = ms.ToArray(); | |||
} | |||
return encryptedBytes; | |||
} | |||
public static byte[] Decrypt(RijndaelManaged cipher, byte[] value) | |||
{ | |||
byte[] decryptedBytes; | |||
using (var decryptor = cipher.CreateDecryptor()) | |||
using (MemoryStream ms = new MemoryStream()) | |||
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) | |||
using (var bw = new BinaryWriter(cs, Encoding.UTF8)) | |||
{ | |||
bw.Write(value); | |||
bw.Close(); | |||
decryptedBytes = ms.ToArray(); | |||
} | |||
return decryptedBytes; | |||
} | |||
public static RijndaelManaged CreateCipher(byte[] key, byte[] iv, int keyLength, int blockSize, int feedbackSize, CipherMode mode, PaddingMode paddingMode) | |||
{ | |||
RijndaelManaged cipher = new RijndaelManaged(); | |||
cipher.Mode = mode; | |||
cipher.Padding = paddingMode; | |||
cipher.Key = key; | |||
cipher.IV = iv; | |||
cipher.KeySize = keyLength; | |||
cipher.BlockSize = blockSize; | |||
cipher.FeedbackSize = feedbackSize; | |||
return cipher; | |||
} | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Security.Cryptography; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Teknik.Utilities.Cryptography | |||
{ | |||
public static class Aes128CFB | |||
{ | |||
public static byte[] Encrypt(byte[] text, byte[] key) | |||
{ | |||
int blockSize = 128; | |||
int keySize = 128; | |||
// Encode the text | |||
string textEnc = Convert.ToBase64String(text); | |||
byte[] textBytes = Encoding.UTF8.GetBytes(textEnc); | |||
// cipherArray | |||
int cipherLen = (blockSize / 8) + textEnc.Length; | |||
byte[] cipherText = new byte[cipherLen]; | |||
Array.Clear(cipherText, 0, cipherLen); | |||
// Create the IV needed for this operation | |||
string ivStr = StringHelper.RandomString(blockSize / 8); | |||
byte[] ivBytes = Encoding.UTF8.GetBytes(ivStr); | |||
// copy IV to the cipher text start | |||
ivBytes.CopyTo(cipherText, 0); | |||
// Process the cipher | |||
ProcessCipher(true, textBytes, key, ivBytes, blockSize, keySize, ref cipherText, blockSize / 8); | |||
return cipherText; | |||
} | |||
public static byte[] Decrypt(byte[] text, byte[] key) | |||
{ | |||
int blockSize = 128; | |||
int keySize = 128; | |||
// Grab the IV and encrypted text from the original text | |||
byte[] ivBytes = text.Take(blockSize / 8).ToArray(); | |||
text = text.Skip(blockSize / 8).Take(text.Length - (blockSize / 8)).ToArray(); | |||
// Process the cipher | |||
ProcessCipher(false, text, key, ivBytes, blockSize, keySize, ref text, 0); | |||
string encodedText = Encoding.UTF8.GetString(text); | |||
return Convert.FromBase64String(encodedText); | |||
} | |||
public static void ProcessCipher(bool encrypt, byte[] text, byte[] key, byte[] iv, int blockSize, int keySize, ref byte[] output, int offset) | |||
{ | |||
using (var cipher = new RijndaelManaged()) | |||
{ | |||
cipher.BlockSize = blockSize; | |||
cipher.KeySize = keySize; | |||
cipher.Mode = CipherMode.CFB; | |||
cipher.FeedbackSize = 8; | |||
cipher.Padding = PaddingMode.None; | |||
cipher.Key = key; | |||
cipher.IV = iv; | |||
using (var encryptor = (encrypt) ? cipher.CreateEncryptor() : cipher.CreateDecryptor()) | |||
using (MemoryStream ms = new MemoryStream()) | |||
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) | |||
using (var bw = new BinaryWriter(cs, Encoding.UTF8)) | |||
{ | |||
bw.Write(text); | |||
bw.Close(); | |||
ms.ToArray().CopyTo(output, offset); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -29,6 +29,12 @@ namespace Teknik.Utilities.Cryptography | |||
} | |||
public static byte[] Hash(byte[] value) | |||
{ | |||
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); | |||
return md5.ComputeHash(value); | |||
} | |||
public static string FileHash(string filename) | |||
{ | |||
try |
@@ -0,0 +1,21 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Teknik.Utilities | |||
{ | |||
public static class DateTimeHelper | |||
{ | |||
public static int GetUnixTimestamp() | |||
{ | |||
return DateTime.UtcNow.GetUnixTimestamp(); | |||
} | |||
public static int GetUnixTimestamp(this DateTime dt) | |||
{ | |||
return (int)(dt.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; | |||
} | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using Org.BouncyCastle.Crypto; | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; |
@@ -1,5 +1,4 @@ | |||
using Org.BouncyCastle.Crypto; | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; |
@@ -8,7 +8,12 @@ namespace Teknik.Utilities | |||
{ | |||
public static class StringHelper | |||
{ | |||
public static string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") | |||
public static string RandomString(int length) | |||
{ | |||
return RandomString(length, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); | |||
} | |||
public static string RandomString(int length, string allowedChars) | |||
{ | |||
const int byteSize = 0x100; | |||
var allowedCharSet = new HashSet<char>(allowedChars).ToArray(); |
@@ -102,6 +102,8 @@ | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="AccountType.cs" /> | |||
<Compile Include="Cryptography\AES.cs" /> | |||
<Compile Include="Cryptography\Aes128CFB.cs" /> | |||
<Compile Include="Cryptography\AesCounterStream.cs" /> | |||
<Compile Include="Cryptography\AesCounterManaged.cs" /> | |||
<Compile Include="Cryptography\AesCounterMode.cs" /> | |||
@@ -111,6 +113,7 @@ | |||
<Compile Include="Cryptography\SHA384.cs" /> | |||
<Compile Include="CurrencyHelper.cs" /> | |||
<Compile Include="CurrencyType.cs" /> | |||
<Compile Include="DateTimeHelper.cs" /> | |||
<Compile Include="EntityExtensions.cs" /> | |||
<Compile Include="FileGenerateResult.cs" /> | |||
<Compile Include="HttpWebResponseResult.cs" /> |
@@ -0,0 +1,38 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Teknik.Utilities; | |||
using Teknik.Utilities.Cryptography; | |||
using Xunit; | |||
namespace Teknik.Tests.UtilitiesTests.Cryptography | |||
{ | |||
public class Aes128Tests | |||
{ | |||
[Fact] | |||
public void Aes128DataTest() | |||
{ | |||
string secret = "426KOBTS66KYLFLQ"; | |||
string key = "u1GIRvmnIFFHLov"; | |||
// Get the Encryption Key from the git secret key | |||
byte[] keyBytes = MD5.Hash(Encoding.UTF8.GetBytes(key)); | |||
// Modify the input secret | |||
byte[] secBytes = Encoding.UTF8.GetBytes(secret); | |||
// Generate the encrypted secret using AES CGM | |||
byte[] encValue = Aes128CFB.Encrypt(secBytes, keyBytes); | |||
string finalSecret = Convert.ToBase64String(encValue); | |||
// Decode it | |||
byte[] decodedSecret = Convert.FromBase64String(finalSecret); | |||
byte[] val = Aes128CFB.Decrypt(decodedSecret, keyBytes); | |||
string verify = Encoding.UTF8.GetString(val); | |||
Assert.Equal(secret, verify); | |||
} | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
// General Information about an assembly is controlled through the following | |||
// set of attributes. Change these attribute values to modify the information | |||
// associated with an assembly. | |||
[assembly: AssemblyTitle("UtilitiesTests")] | |||
[assembly: AssemblyDescription("")] | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("")] | |||
[assembly: AssemblyProduct("Teknik")] | |||
[assembly: AssemblyCopyright("Copyright © 2017")] | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
// Setting ComVisible to false makes the types in this assembly not visible | |||
// to COM components. If you need to access a type in this assembly from | |||
// COM, set the ComVisible attribute to true on that type. | |||
[assembly: ComVisible(false)] | |||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||
[assembly: Guid("88deb506-3f7e-4b39-8264-861976dc7434")] | |||
// Version information for an assembly consists of the following four values: | |||
// | |||
// Major Version | |||
// Minor Version | |||
// Build Number | |||
// Revision | |||
// | |||
// You can specify all the values or you can default the Build and Revision Numbers | |||
// by using the '*' as shown below: | |||
// [assembly: AssemblyVersion("1.0.*")] | |||
[assembly: AssemblyVersion("1.0.0.0")] | |||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -0,0 +1,90 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Import Project="..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props" Condition="Exists('..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props')" /> | |||
<Import Project="..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" /> | |||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||
<ProjectGuid>{88DEB506-3F7E-4B39-8264-861976DC7434}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Teknik.Tests.UtilitiesTests</RootNamespace> | |||
<AssemblyName>UtilitiesTests</AssemblyName> | |||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion> | |||
<FileAlignment>512</FileAlignment> | |||
<NuGetPackageImportStamp> | |||
</NuGetPackageImportStamp> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Net.Http" /> | |||
<Reference Include="System.Xml" /> | |||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.assert, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.core, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="xunit.execution.desktop, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="Cryptography\Aes128Tests.cs" /> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Utilities\Utilities\Utilities.csproj"> | |||
<Project>{F45DE6FC-3754-4954-A20A-4277362CC6C1}</Project> | |||
<Name>Utilities</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> | |||
<PropertyGroup> | |||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> | |||
</PropertyGroup> | |||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.2.0\build\net20\xunit.runner.visualstudio.props'))" /> | |||
<Error Condition="!Exists('..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.msbuild.2.2.0\build\net452\xunit.runner.msbuild.props'))" /> | |||
</Target> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
<Target Name="BeforeBuild"> | |||
</Target> | |||
<Target Name="AfterBuild"> | |||
</Target> | |||
--> | |||
</Project> |
@@ -0,0 +1,12 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="xunit" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net462" /> | |||
<package id="xunit.assert" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.core" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.extensibility.core" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.extensibility.execution" version="2.2.0" targetFramework="net462" /> | |||
<package id="xunit.runner.console" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
<package id="xunit.runner.msbuild" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
<package id="xunit.runner.visualstudio" version="2.2.0" targetFramework="net462" developmentDependency="true" /> | |||
</packages> |