mirror of
https://github.com/Jackett/Jackett
synced 2025-02-25 07:32:38 +00:00
Updated encryptioon service for better use with Docker
This commit is contained in:
parent
6f475b18f3
commit
50d931b4fb
3 changed files with 148 additions and 1 deletions
|
@ -319,6 +319,7 @@
|
|||
<Compile Include="Startup.cs" />
|
||||
<Compile Include="Models\TorznabQuery.cs" />
|
||||
<Compile Include="CurlHelper.cs" />
|
||||
<Compile Include="Utils\StringCipher.cs" />
|
||||
<Compile Include="Utils\StringUtil.cs" />
|
||||
<Compile Include="Utils\TorznabCapsUtil.cs" />
|
||||
<Compile Include="Utils\Clients\UnixSafeCurlWebClient.cs" />
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Reflection;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jackett.Utils;
|
||||
|
||||
namespace Jackett.Services
|
||||
{
|
||||
|
@ -18,6 +19,7 @@ namespace Jackett.Services
|
|||
public class ProtectionService : IProtectionService
|
||||
{
|
||||
DataProtectionScope PROTECTION_SCOPE = DataProtectionScope.LocalMachine;
|
||||
private const string JACKETT_KEY = "JACKETT_KEY";
|
||||
const string APPLICATION_KEY = "Dvz66r3n8vhTGip2/quiw5ISyM37f7L2iOdupzdKmzkvXGhAgQiWK+6F+4qpxjPVNks1qO7LdWuVqRlzgLzeW8mChC6JnBMUS1Fin4N2nS9lh4XPuCZ1che75xO92Nk2vyXUo9KSFG1hvEszAuLfG2Mcg1r0sVyVXd2gQDU/TbY=";
|
||||
|
||||
IServerService serverService;
|
||||
|
@ -34,6 +36,34 @@ namespace Jackett.Services
|
|||
}
|
||||
|
||||
public string Protect(string plainText)
|
||||
{
|
||||
var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY);
|
||||
|
||||
if (jackettKey == null)
|
||||
{
|
||||
return ProtectDefaultMethod(plainText);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ProtectUsingKey(plainText, jackettKey);
|
||||
}
|
||||
}
|
||||
|
||||
public string UnProtect(string plainText)
|
||||
{
|
||||
var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY);
|
||||
|
||||
if (jackettKey == null)
|
||||
{
|
||||
return UnProtectDefaultMethod(plainText);
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnProtectUsingKey(plainText, jackettKey);
|
||||
}
|
||||
}
|
||||
|
||||
private string ProtectDefaultMethod(string plainText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plainText))
|
||||
return string.Empty;
|
||||
|
@ -72,7 +102,7 @@ namespace Jackett.Services
|
|||
return Convert.ToBase64String(protectedBytes);
|
||||
}
|
||||
|
||||
public string UnProtect(string plainText)
|
||||
private string UnProtectDefaultMethod(string plainText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plainText))
|
||||
return string.Empty;
|
||||
|
@ -111,6 +141,16 @@ namespace Jackett.Services
|
|||
return Encoding.UTF8.GetString(unprotectedBytes);
|
||||
}
|
||||
|
||||
private string ProtectUsingKey(string plainText, string key)
|
||||
{
|
||||
return StringCipher.Encrypt(plainText, key);
|
||||
}
|
||||
|
||||
private string UnProtectUsingKey(string plainText, string key)
|
||||
{
|
||||
return StringCipher.Decrypt(plainText, key);
|
||||
}
|
||||
|
||||
public void Protect<T>(T obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
|
|
106
src/Jackett/Utils/StringCipher.cs
Normal file
106
src/Jackett/Utils/StringCipher.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Jackett.Utils
|
||||
{
|
||||
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))
|
||||
{
|
||||
var plainTextBytes = new byte[cipherTextBytes.Length];
|
||||
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
|
||||
memoryStream.Close();
|
||||
cryptoStream.Close();
|
||||
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue