1. AES Encryption/Decryption Tool
2. Encrypted Connection string 3. Added API Security using ApiKey
This commit is contained in:
parent
4c6f9a4ba8
commit
21e02ab3ca
1
.gitignore
vendored
1
.gitignore
vendored
@ -361,3 +361,4 @@ MigrationBackup/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
/PortBlog.API/appsettings.Production.json
|
||||
|
||||
10
AesEncryption/AesEncryption.csproj
Normal file
10
AesEncryption/AesEncryption.csproj
Normal 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
138
AesEncryption/Program.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34701.34
|
||||
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
|
||||
Global
|
||||
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}.Release|Any CPU.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
44
PortBlog.API/Extensions/ConfigurationExtensions.cs
Normal file
44
PortBlog.API/Extensions/ConfigurationExtensions.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
PortBlog.API/Middleware/ApiKeyMiddleware.cs
Normal file
40
PortBlog.API/Middleware/ApiKeyMiddleware.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,5 +19,11 @@
|
||||
public int Views { get; set; } = 0;
|
||||
|
||||
public int Comments { get; set; } = 0;
|
||||
|
||||
public string? Image { get; set; }
|
||||
|
||||
public string? CreatedDate { get; set; }
|
||||
|
||||
public string? ModifiedDate { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,5 +31,13 @@
|
||||
public ICollection<HobbyDto> Hobbies { get; set; } = new List<HobbyDto>();
|
||||
|
||||
public ICollection<ProjectDto> Projects { get; set; } = new List<ProjectDto>();
|
||||
|
||||
public ICollection<string> ProjectsCategories
|
||||
{
|
||||
get
|
||||
{
|
||||
return Projects.Select(p => p.Category).Distinct().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,15 @@ namespace PortBlog.API.Profiles
|
||||
public BlogProfile()
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ namespace PortBlog.API.Profiles
|
||||
CreateMap<Experience, ExperienceDto>()
|
||||
.ForMember(
|
||||
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
|
||||
(
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using PortBlog.API.DbContexts;
|
||||
using PortBlog.API.Extensions;
|
||||
using PortBlog.API.Middleware;
|
||||
using Serilog;
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
@ -25,10 +27,42 @@ builder.Services.AddProblemDetails();
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
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");
|
||||
|
||||
if (builder.Configuration.GetValue<bool>("ConnectionStrings:Encryption"))
|
||||
{
|
||||
connectionString = builder.Configuration.DecryptConnectionString(connectionString);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
throw new Exception("Connection string cannot be empty");
|
||||
@ -66,6 +100,8 @@ app.UseStaticFiles(new StaticFileOptions()
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseMiddleware<ApiKeyMiddleware>();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
@ -24,7 +24,7 @@ namespace PortBlog.API.Repositories
|
||||
.ThenInclude(e => e.Details)
|
||||
.Include(r => r.SocialLinks)
|
||||
.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.Certifications)
|
||||
.Include(r => r.Skills)
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
{
|
||||
"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": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"XApiKey": "c6eAXYcNT873TT7BfMgQyS4ii7hxa53TLEUN7pAGaaU="
|
||||
}
|
||||
|
||||
@ -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": "*"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user