You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
9.4 KiB
211 lines
9.4 KiB
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using API_NetFramework.Models;
|
|
using Swashbuckle.Application;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using System.Web.Configuration;
|
|
|
|
namespace SecuringWebApiUsingApiKey.Middleware
|
|
{
|
|
public static class StringCipher
|
|
{
|
|
// This constant is used to determine the keysize of the encryption algorithm in bits.
|
|
// We divide this by 8 within the code below to get the equivalent number of bytes.
|
|
private const int Keysize = 256;
|
|
|
|
// This constant determines the number of iterations for the password bytes generation function.
|
|
private const int DerivationIterations = 1000;
|
|
|
|
public static string Encrypt(string plainText, string passPhrase)
|
|
{
|
|
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
|
|
// so that the same Salt and IV values can be used when decrypting.
|
|
var saltStringBytes = Generate256BitsOfRandomEntropy();
|
|
var ivStringBytes = Generate256BitsOfRandomEntropy();
|
|
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
|
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
|
{
|
|
var keyBytes = password.GetBytes(Keysize / 8);
|
|
using (var symmetricKey = new RijndaelManaged())
|
|
{
|
|
symmetricKey.BlockSize = 256;
|
|
symmetricKey.Mode = CipherMode.CBC;
|
|
symmetricKey.Padding = PaddingMode.PKCS7;
|
|
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
|
|
{
|
|
using (var memoryStream = new MemoryStream())
|
|
{
|
|
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
|
{
|
|
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
|
|
cryptoStream.FlushFinalBlock();
|
|
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
|
var cipherTextBytes = saltStringBytes;
|
|
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
|
|
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
|
|
memoryStream.Close();
|
|
cryptoStream.Close();
|
|
return Convert.ToBase64String(cipherTextBytes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string Decrypt(string cipherText, string passPhrase)
|
|
{
|
|
// Get the complete stream of bytes that represent:
|
|
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
|
|
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
|
|
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
|
|
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
|
|
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
|
|
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
|
|
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
|
|
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
|
|
|
|
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
|
{
|
|
var keyBytes = password.GetBytes(Keysize / 8);
|
|
using (var symmetricKey = new RijndaelManaged())
|
|
{
|
|
symmetricKey.BlockSize = 256;
|
|
symmetricKey.Mode = CipherMode.CBC;
|
|
symmetricKey.Padding = PaddingMode.PKCS7;
|
|
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
|
|
{
|
|
using (var memoryStream = new MemoryStream(cipherTextBytes))
|
|
{
|
|
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
|
using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
|
|
{
|
|
return streamReader.ReadToEnd();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static byte[] Generate256BitsOfRandomEntropy()
|
|
{
|
|
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
|
|
using (var rngCsp = new RNGCryptoServiceProvider())
|
|
{
|
|
// Fill the array with cryptographically secure random bytes.
|
|
rngCsp.GetBytes(randomBytes);
|
|
}
|
|
return randomBytes;
|
|
}
|
|
}
|
|
public static class ApiKeyMiddleware
|
|
{
|
|
public static string[] apikeys;
|
|
|
|
public static string GetValue( string key)
|
|
{
|
|
string res = WebConfigurationManager.AppSettings[key];
|
|
return res;
|
|
}
|
|
|
|
private static bool checkfunction(string apikey, string function)
|
|
{
|
|
string decryptstring = SecuringWebApiUsingApiKey.Middleware.StringCipher.Decrypt(apikey, "OnDoc01");
|
|
if ( decryptstring.Contains(function))
|
|
{ return true; }
|
|
else return false;
|
|
}
|
|
public static Boolean Authorized(HttpRequestMessage request, string function)
|
|
{
|
|
|
|
if (GetValue("AuthCheck") == "Yes")
|
|
{
|
|
apikeys = GetValue("APIKeys").ToString().Split(',');
|
|
for (int i = 0; i < apikeys.Length; i++)
|
|
{
|
|
apikeys[i] = apikeys[i].Replace(Environment.NewLine, "");
|
|
}
|
|
IEnumerable<KeyValuePair<string, string>> queryParams = request.GetQueryNameValuePairs();
|
|
var key = queryParams.FirstOrDefault(x => x.Key == "api_key");
|
|
if (apikeys.Contains(key.Value) && checkfunction(key.Value,function)==true) { return true; }
|
|
try
|
|
{
|
|
IEnumerable<string> headerValues = request.Headers.GetValues("api_key");
|
|
string apikey = headerValues.FirstOrDefault();
|
|
|
|
if (apikeys.Contains(apikey) && checkfunction(apikey,function)==true) { return true; }
|
|
}
|
|
catch { }
|
|
try
|
|
{
|
|
if (request.Headers.Authorization.Scheme == "Bearer" && apikeys.Contains(request.Headers.Authorization.Parameter.ToString()) && checkfunction(request.Headers.Authorization.Parameter.ToString(),function)==true)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
catch {
|
|
APILogging.Log(request, "Unberechtigter Zugriff", LogLevelType.Error);
|
|
return false; }
|
|
}
|
|
APILogging.Log(request, "Unberechtigter Zugriff", LogLevelType.Error);
|
|
return false;
|
|
}
|
|
//private readonly RequestDelegate _next;
|
|
//private const string APIKEYNAME = "ApiKey";
|
|
//public ApiKeyMiddleware(RequestDelegate next)
|
|
//{
|
|
// _next = next;
|
|
//}
|
|
//public async Task InvokeAsync(Microsoft.AspNetCore.Http.HttpContext context)
|
|
//{
|
|
// var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
|
|
// string apiCheck = GetValue("ApiCheck");
|
|
// if (apiCheck == "e913aab4-c2c5-4e33-ad24-d25848f748e7")
|
|
// {
|
|
// await _next(context);
|
|
// return;
|
|
// }
|
|
// if (!context.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
|
|
// {
|
|
// context.Response.StatusCode = 401;
|
|
// await context.Response.WriteAsync("Api Key was not provided. (Using ApiKeyMiddleware) ");
|
|
// return;
|
|
// }
|
|
|
|
|
|
|
|
// var apiKey = GetValue(APIKEYNAME);
|
|
// string[] keys = apiKey.Split(',');
|
|
|
|
// bool tokenok = false;
|
|
// for (int i = 0; i < keys.Length; i++)
|
|
// if (keys[i] == extractedApiKey)
|
|
// {
|
|
// tokenok = true;
|
|
// break;
|
|
// }
|
|
|
|
// //if (!apiKey.Equals(extractedApiKey))
|
|
// if (!tokenok)
|
|
// {
|
|
// context.Response.StatusCode = 401;
|
|
// await context.Response.WriteAsync
|
|
// ("Unauthorized client. (Using ApiKeyMiddleware)");
|
|
// return;
|
|
// }
|
|
|
|
// await _next(context);
|
|
//}
|
|
}
|
|
} |