1. AES Encryption/Decryption Tool

2. Encrypted Connection string
3. Added API Security using ApiKey
This commit is contained in:
Bangara Raju Kottedi 2024-04-28 13:22:57 +05:30
parent 4c6f9a4ba8
commit 21e02ab3ca
14 changed files with 308 additions and 20 deletions

3
.gitignore vendored
View File

@ -360,4 +360,5 @@ MigrationBackup/
.ionide/ .ionide/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
/PortBlog.API/appsettings.Production.json

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

138
AesEncryption/Program.cs Normal file
View File

@ -0,0 +1,138 @@
// See https://aka.ms/new-console-template for more information
using System.Security.Cryptography;
string keyBase64;
string cipherText;
string vectorBase64;
string plainText;
Console.WriteLine("Welcome to the Aes Encryption/Decryption tool");
Select:
Console.WriteLine("Please select the action you want to perform: /n Press 1 to Generate Key. /n Press 2 to Encrypt using the key. /n Press 3 to Decrpt using the key.");
string? action = Console.ReadLine();
if (action == null || !int.TryParse(action, out int actionId) || !new List<int>{ 1, 2, 3 }.Contains(actionId))
{
Console.WriteLine("Invalid option. /n");
goto Select;
}
switch (actionId)
{
case 1:
Console.WriteLine("Creating Aes Encryption 256 bit key");
using (Aes aesAlgorithm = Aes.Create())
{
aesAlgorithm.KeySize = 256;
aesAlgorithm.GenerateKey();
keyBase64 = Convert.ToBase64String(aesAlgorithm.Key);
Console.WriteLine($"Aes Key Size : {aesAlgorithm.KeySize}");
Console.WriteLine("Here is the Aes key in Base64:");
Console.WriteLine(keyBase64);
}
break;
case 2:
Console.WriteLine("Encrypt Text");
Console.WriteLine("Provide the Aes Key in base64 format :");
keyBase64 = Console.ReadLine();
Console.WriteLine("--------------------------------------------------------------");
Console.WriteLine("Please enter the text that you want to encrypt:");
plainText = Console.ReadLine();
Console.WriteLine("--------------------------------------------------------------");
cipherText = EncryptDataWithAes(plainText, keyBase64, out vectorBase64);
Console.WriteLine("--------------------------------------------------------------");
Console.WriteLine("Here is the cipher text with vector:");
Console.WriteLine(cipherText + ":" + vectorBase64);
break;
case 3:
Console.WriteLine("Please enter the text that you want to decrypt:");
cipherText = Console.ReadLine();
Console.WriteLine("--------------------------------------------------------------");
Console.WriteLine("Provide the Aes Key:");
keyBase64 = Console.ReadLine();
Console.WriteLine("--------------------------------------------------------------");
vectorBase64 = cipherText.Split(":")[1];
cipherText = cipherText.Split(":")[0];
plainText = DecryptDataWithAes(cipherText, keyBase64, vectorBase64);
Console.WriteLine("--------------------------------------------------------------");
Console.WriteLine("Here is the decrypted data:");
Console.WriteLine(plainText);
break;
}
goto Select;
static string EncryptDataWithAes(string plainText, string keyBase64, out string vectorBase64)
{
using (Aes aesAlgorithm = Aes.Create())
{
aesAlgorithm.Key = Convert.FromBase64String(keyBase64);
aesAlgorithm.GenerateIV();
Console.WriteLine($"Aes Cipher Mode : {aesAlgorithm.Mode}");
Console.WriteLine($"Aes Padding Mode: {aesAlgorithm.Padding}");
Console.WriteLine($"Aes Key Size : {aesAlgorithm.KeySize}");
//set the parameters with out keyword
vectorBase64 = Convert.ToBase64String(aesAlgorithm.IV);
// Create encryptor object
ICryptoTransform encryptor = aesAlgorithm.CreateEncryptor();
byte[] encryptedData;
//Encryption will be done in a memory stream through a CryptoStream object
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
encryptedData = ms.ToArray();
}
}
return Convert.ToBase64String(encryptedData);
}
}
static string DecryptDataWithAes(string cipherText, string keyBase64, string vectorBase64)
{
using (Aes aesAlgorithm = Aes.Create())
{
aesAlgorithm.Key = Convert.FromBase64String(keyBase64);
aesAlgorithm.IV = Convert.FromBase64String(vectorBase64);
Console.WriteLine($"Aes Cipher Mode : {aesAlgorithm.Mode}");
Console.WriteLine($"Aes Padding Mode: {aesAlgorithm.Padding}");
Console.WriteLine($"Aes Key Size : {aesAlgorithm.KeySize}");
Console.WriteLine($"Aes Block Size : {aesAlgorithm.BlockSize}");
// Create decryptor object
ICryptoTransform decryptor = aesAlgorithm.CreateDecryptor();
byte[] cipher = Convert.FromBase64String(cipherText);
//Decryption will be done in a memory stream through a CryptoStream object
using (MemoryStream ms = new MemoryStream(cipher))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
return sr.ReadToEnd();
}
}
}
}
}

View File

@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.9.34701.34 VisualStudioVersion = 17.9.34701.34
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortBlog.API", "PortBlog.API\PortBlog.API.csproj", "{2E50B5D7-56E2-4E89-8742-BB57FF4245F9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortBlog.API", "PortBlog.API\PortBlog.API.csproj", "{2E50B5D7-56E2-4E89-8742-BB57FF4245F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AesEncryption", "AesEncryption\AesEncryption.csproj", "{26654BFD-EE9B-49BA-84BA-9156AC348076}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -15,6 +17,10 @@ Global
{2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Release|Any CPU.Build.0 = Release|Any CPU {2E50B5D7-56E2-4E89-8742-BB57FF4245F9}.Release|Any CPU.Build.0 = Release|Any CPU
{26654BFD-EE9B-49BA-84BA-9156AC348076}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26654BFD-EE9B-49BA-84BA-9156AC348076}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26654BFD-EE9B-49BA-84BA-9156AC348076}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26654BFD-EE9B-49BA-84BA-9156AC348076}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,44 @@
using System.Security.Cryptography;
namespace PortBlog.API.Extensions
{
public static class ConfigurationExtensions
{
public static string DecryptConnectionString(this IConfiguration configuration, string encryptedConnectionString)
{
string keyBase64 = configuration.GetValue<string>("ConnectionStrings:Key").ToString();
string vectorBase64 = encryptedConnectionString.Split(":")[1];
string cipherText = encryptedConnectionString.Split(":")[0];
using (Aes aesAlgorithm = Aes.Create())
{
aesAlgorithm.Key = Convert.FromBase64String(keyBase64);
aesAlgorithm.IV = Convert.FromBase64String(vectorBase64);
Console.WriteLine($"Aes Cipher Mode : {aesAlgorithm.Mode}");
Console.WriteLine($"Aes Padding Mode: {aesAlgorithm.Padding}");
Console.WriteLine($"Aes Key Size : {aesAlgorithm.KeySize}");
Console.WriteLine($"Aes Block Size : {aesAlgorithm.BlockSize}");
// Create decryptor object
ICryptoTransform decryptor = aesAlgorithm.CreateDecryptor();
byte[] cipher = Convert.FromBase64String(cipherText);
//Decryption will be done in a memory stream through a CryptoStream object
using (MemoryStream ms = new MemoryStream(cipher))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
return sr.ReadToEnd();
}
}
}
}
}
}
}

View File

@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace PortBlog.API.Middleware
{
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string APIKEY = "XApiKey";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(APIKEY, out var extractedApiKey))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Api key was not provided");
return;
}
var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
var apiKey = appSettings.GetValue<string>(APIKEY);
if (apiKey != null && !apiKey.Equals(extractedApiKey))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Unauthorized client");
return;
}
await _next(context);
}
}
}

View File

@ -19,5 +19,11 @@
public int Views { get; set; } = 0; public int Views { get; set; } = 0;
public int Comments { get; set; } = 0; public int Comments { get; set; } = 0;
public string? Image { get; set; }
public string? CreatedDate { get; set; }
public string? ModifiedDate { get; set; }
} }
} }

View File

@ -31,5 +31,13 @@
public ICollection<HobbyDto> Hobbies { get; set; } = new List<HobbyDto>(); public ICollection<HobbyDto> Hobbies { get; set; } = new List<HobbyDto>();
public ICollection<ProjectDto> Projects { get; set; } = new List<ProjectDto>(); public ICollection<ProjectDto> Projects { get; set; } = new List<ProjectDto>();
public ICollection<string> ProjectsCategories
{
get
{
return Projects.Select(p => p.Category).Distinct().ToList();
}
}
} }
} }

View File

@ -9,7 +9,15 @@ namespace PortBlog.API.Profiles
public BlogProfile() public BlogProfile()
{ {
CreateMap<Blog, BlogDto>(); CreateMap<Blog, BlogDto>();
CreateMap<Post, PostDto>(); CreateMap<Post, PostDto>()
.ForMember(
dest => dest.CreatedDate,
opts => opts.MapFrom(src => src.CreatedDate != null ? src.CreatedDate.Value.ToString("MMM dd, yyyy") : string.Empty)
)
.ForMember(
dest => dest.ModifiedDate,
opts => opts.MapFrom(src => src.CreatedDate != null ? src.ModifiedDate.Value.ToString("MMM dd, yyyy") : string.Empty)
);
} }
} }
} }

View File

@ -24,7 +24,7 @@ namespace PortBlog.API.Profiles
CreateMap<Experience, ExperienceDto>() CreateMap<Experience, ExperienceDto>()
.ForMember( .ForMember(
dest => dest.Period, dest => dest.Period,
src => src.MapFrom(src => src.StartDate.Year + " - " + (src.EndDate != null ? src.EndDate.Value.Year : "Present")) src => src.MapFrom(src => src.StartDate.ToString("MMM yyyy") + " - " + (src.EndDate != null ? src.EndDate.Value.ToString("MMM yyyy") : "Present"))
) )
.ForMember .ForMember
( (

View File

@ -1,7 +1,9 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.OpenApi.Models;
using PortBlog.API.DbContexts; using PortBlog.API.DbContexts;
using PortBlog.API.Extensions; using PortBlog.API.Extensions;
using PortBlog.API.Middleware;
using Serilog; using Serilog;
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
@ -25,10 +27,42 @@ builder.Services.AddProblemDetails();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{
Description = "ApiKey must appear in header",
Type = SecuritySchemeType.ApiKey,
Name = "XApiKey",
In = ParameterLocation.Header,
Scheme = "ApiKeyScheme"
});
var key = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "ApiKey"
},
In = ParameterLocation.Header
};
var requirement = new OpenApiSecurityRequirement()
{
{key, new List<string> {} }
};
c.AddSecurityRequirement(requirement);
});
var connectionString = builder.Configuration.GetConnectionString("PortBlogDBConnectionString"); var connectionString = builder.Configuration.GetConnectionString("PortBlogDBConnectionString");
if (builder.Configuration.GetValue<bool>("ConnectionStrings:Encryption"))
{
connectionString = builder.Configuration.DecryptConnectionString(connectionString);
}
if (string.IsNullOrEmpty(connectionString)) if (string.IsNullOrEmpty(connectionString))
{ {
throw new Exception("Connection string cannot be empty"); throw new Exception("Connection string cannot be empty");
@ -66,6 +100,8 @@ app.UseStaticFiles(new StaticFileOptions()
app.UseAuthorization(); app.UseAuthorization();
app.UseMiddleware<ApiKeyMiddleware>();
app.MapControllers(); app.MapControllers();
app.Run(); app.Run();

View File

@ -24,7 +24,7 @@ namespace PortBlog.API.Repositories
.ThenInclude(e => e.Details) .ThenInclude(e => e.Details)
.Include(r => r.SocialLinks) .Include(r => r.SocialLinks)
.ThenInclude(s => s.Blog) .ThenInclude(s => s.Blog)
.ThenInclude(b => b.Posts.Take(5)) .ThenInclude(b => b.Posts.OrderByDescending(p => p.Likes).Take(5))
.Include(r => r.Hobbies) .Include(r => r.Hobbies)
.Include(r => r.Certifications) .Include(r => r.Certifications)
.Include(r => r.Skills) .Include(r => r.Skills)

View File

@ -1,11 +1,14 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"PortBlogDBConnectionString": "SERVER=192.168.0.197; DATABASE=cv_blog; UID=PortBlogDevUser; PWD=p@$$w0rd1234" "PortBlogDBConnectionString": "SERVER=192.168.0.197; DATABASE=cv_blog; UID=PortBlogDevUser; PWD=p@$$w0rd1234",
"Encryption": "false",
"Key": "rgdBsYjrgQV9YaE+6QFK5oyTOWwbl2bSWkuc2JXcIyw="
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
} },
"XApiKey": "c6eAXYcNT873TT7BfMgQyS4ii7hxa53TLEUN7pAGaaU="
} }

View File

@ -1,12 +0,0 @@
{
"ConnectionStrings": {
"PortBlogDBConnectionString": "SERVER=10.1.0.10;DATABASE=cv_blog;UID=PortBlogProdUser;PWD=pr0dp@$$w0rd6534"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}