encryption: bugfix
This commit is contained in:
parent
7b1de6b36a
commit
eb18133e4b
@ -34,6 +34,7 @@ using System.Web;
|
|||||||
using ASC.Common.Logging;
|
using ASC.Common.Logging;
|
||||||
using ASC.Core;
|
using ASC.Core;
|
||||||
using ASC.Data.Storage.Configuration;
|
using ASC.Data.Storage.Configuration;
|
||||||
|
using ASC.Data.Storage.Encryption;
|
||||||
using ASC.Security.Cryptography;
|
using ASC.Security.Cryptography;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
@ -76,6 +76,7 @@ namespace ASC.Data.Storage.Configuration
|
|||||||
public bool Public { get; set; }
|
public bool Public { get; set; }
|
||||||
public bool DisableMigrate { get; set; }
|
public bool DisableMigrate { get; set; }
|
||||||
public bool Count { get; set; } = true;
|
public bool Count { get; set; } = true;
|
||||||
|
public bool DisabledEncryption { get; set; }
|
||||||
|
|
||||||
public IEnumerable<Module> Domain { get; set; }
|
public IEnumerable<Module> Domain { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ using System.Linq;
|
|||||||
using ASC.Common.Logging;
|
using ASC.Common.Logging;
|
||||||
using ASC.Core;
|
using ASC.Core;
|
||||||
using ASC.Data.Storage.Configuration;
|
using ASC.Data.Storage.Configuration;
|
||||||
|
using ASC.Data.Storage.Encryption;
|
||||||
using ASC.Security.Cryptography;
|
using ASC.Security.Cryptography;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -42,6 +43,9 @@ namespace ASC.Data.Storage.DiscStorage
|
|||||||
public class DiscDataStore : BaseStorage
|
public class DiscDataStore : BaseStorage
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, MappedPath> _mappedPaths = new Dictionary<string, MappedPath>();
|
private readonly Dictionary<string, MappedPath> _mappedPaths = new Dictionary<string, MappedPath>();
|
||||||
|
private ICrypt Crypt { get; set; }
|
||||||
|
private EncryptionSettingsHelper EncryptionSettingsHelper { get; set; }
|
||||||
|
private EncryptionFactory EncryptionFactory { get; set; }
|
||||||
|
|
||||||
public override IDataStore Configure(string tenant, Handler handlerConfig, Module moduleConfig, IDictionary<string, string> props)
|
public override IDataStore Configure(string tenant, Handler handlerConfig, Module moduleConfig, IDictionary<string, string> props)
|
||||||
{
|
{
|
||||||
@ -62,6 +66,9 @@ namespace ASC.Data.Storage.DiscStorage
|
|||||||
ToDictionary(x => x.Name,
|
ToDictionary(x => x.Name,
|
||||||
y => y.Expires);
|
y => y.Expires);
|
||||||
_domainsExpires.Add(string.Empty, moduleConfig.Expires);
|
_domainsExpires.Add(string.Empty, moduleConfig.Expires);
|
||||||
|
var settings = moduleConfig.DisabledEncryption ? new EncryptionSettings() : EncryptionSettingsHelper.Load();
|
||||||
|
Crypt = EncryptionFactory.GetCrypt(moduleConfig.Name, settings);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,9 +77,13 @@ namespace ASC.Data.Storage.DiscStorage
|
|||||||
PathUtils pathUtils,
|
PathUtils pathUtils,
|
||||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
IOptionsMonitor<ILog> options)
|
IOptionsMonitor<ILog> options,
|
||||||
|
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||||
|
EncryptionFactory encryptionFactory)
|
||||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
: base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||||
{
|
{
|
||||||
|
EncryptionSettingsHelper = encryptionSettingsHelper;
|
||||||
|
EncryptionFactory = encryptionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetPhysicalPath(string domain, string path)
|
public string GetPhysicalPath(string domain, string path)
|
||||||
@ -676,7 +687,7 @@ namespace ASC.Data.Storage.DiscStorage
|
|||||||
|
|
||||||
if (File.Exists(target))
|
if (File.Exists(target))
|
||||||
{
|
{
|
||||||
new FileInfo(target).Encrypt();
|
Crypt.EncryptFile(target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -692,7 +703,7 @@ namespace ASC.Data.Storage.DiscStorage
|
|||||||
|
|
||||||
if (File.Exists(target))
|
if (File.Exists(target))
|
||||||
{
|
{
|
||||||
new FileInfo(target).Decrypt();
|
Crypt.DecryptFile(target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
337
common/ASC.Data.Storage/Encryption/Crypt.cs
Normal file
337
common/ASC.Data.Storage/Encryption/Crypt.cs
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
using ASC.Common;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public class Crypt : ICrypt
|
||||||
|
{
|
||||||
|
private string Storage { get; set; }
|
||||||
|
private EncryptionSettings Settings { get; set; }
|
||||||
|
private string TempDir { get; set; }
|
||||||
|
|
||||||
|
private IConfiguration Configuration { get; set; }
|
||||||
|
private EncryptionFactory EncryptionFactory { get; set; }
|
||||||
|
|
||||||
|
public void Init(string storageName, EncryptionSettings encryptionSettings)
|
||||||
|
{
|
||||||
|
Storage = storageName;
|
||||||
|
Settings = encryptionSettings;
|
||||||
|
TempDir = Configuration["storage:encryption:tempdir"] ?? Path.GetTempPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Crypt(IConfiguration configuration, EncryptionFactory encryptionFactory)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
EncryptionFactory = encryptionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Version { get { return 1; } }
|
||||||
|
|
||||||
|
public void EncryptFile(string filePath)
|
||||||
|
{
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(Settings.Password);
|
||||||
|
|
||||||
|
using (var fileStream = File.OpenRead(filePath))
|
||||||
|
{
|
||||||
|
if (metadata.TryReadFromStream(fileStream, Version))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptFile(filePath, Settings.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecryptFile(string filePath)
|
||||||
|
{
|
||||||
|
if (Settings.Status == EncryprtionStatus.Decrypted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecryptFile(filePath, Settings.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetReadStream(string filePath)
|
||||||
|
{
|
||||||
|
if (Settings.Status == EncryprtionStatus.Decrypted)
|
||||||
|
{
|
||||||
|
return File.OpenRead(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetReadStream(filePath, Settings.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GetFileSize(string filePath)
|
||||||
|
{
|
||||||
|
if (Settings.Status == EncryprtionStatus.Decrypted)
|
||||||
|
{
|
||||||
|
return new FileInfo(filePath).Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetFileSize(filePath, Settings.Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void EncryptFile(string filePath, string password)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(password)) return;
|
||||||
|
|
||||||
|
var fileInfo = new FileInfo(filePath);
|
||||||
|
|
||||||
|
if (fileInfo.IsReadOnly)
|
||||||
|
{
|
||||||
|
fileInfo.IsReadOnly = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ecryptedFilePath = GetUniqFileName(filePath, ".enc");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(Version, password, fileInfo.Length);
|
||||||
|
|
||||||
|
using (var ecryptedFileStream = new FileStream(ecryptedFilePath, FileMode.Create))
|
||||||
|
{
|
||||||
|
metadata.WriteToStream(ecryptedFileStream);
|
||||||
|
|
||||||
|
using (var algorithm = metadata.GetCryptographyAlgorithm())
|
||||||
|
{
|
||||||
|
using (var transform = algorithm.CreateEncryptor())
|
||||||
|
{
|
||||||
|
using (var cryptoStream = new CryptoStreamWrapper(ecryptedFileStream, transform, CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
using (var fileStream = File.OpenRead(filePath))
|
||||||
|
{
|
||||||
|
fileStream.CopyTo(cryptoStream);
|
||||||
|
fileStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
|
|
||||||
|
metadata.ComputeAndWriteHmacHash(ecryptedFileStream);
|
||||||
|
|
||||||
|
cryptoStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecryptedFileStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplaceFile(ecryptedFilePath, filePath);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
if (File.Exists(ecryptedFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(ecryptedFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DecryptFile(string filePath, string password)
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(filePath);
|
||||||
|
|
||||||
|
if (fileInfo.IsReadOnly)
|
||||||
|
{
|
||||||
|
fileInfo.IsReadOnly = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var decryptedFilePath = GetUniqFileName(filePath, ".dec");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(password);
|
||||||
|
|
||||||
|
using (var fileStream = File.OpenRead(filePath))
|
||||||
|
{
|
||||||
|
if (!metadata.TryReadFromStream(fileStream, Version)) return;
|
||||||
|
|
||||||
|
metadata.ComputeAndValidateHmacHash(fileStream);
|
||||||
|
|
||||||
|
using (var decryptedFileStream = new FileStream(decryptedFilePath, FileMode.Create))
|
||||||
|
{
|
||||||
|
using (var algorithm = metadata.GetCryptographyAlgorithm())
|
||||||
|
{
|
||||||
|
using (var transform = algorithm.CreateDecryptor())
|
||||||
|
{
|
||||||
|
using (var cryptoStream = new CryptoStreamWrapper(decryptedFileStream, transform, CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
fileStream.CopyTo(cryptoStream);
|
||||||
|
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
|
cryptoStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptedFileStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplaceFile(decryptedFilePath, filePath);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
if (File.Exists(decryptedFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(decryptedFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream GetReadMemoryStream(string filePath, string password)
|
||||||
|
{
|
||||||
|
var decryptedMemoryStream = new MemoryStream(); //TODO: MemoryStream or temporary decrypted file on disk?
|
||||||
|
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(password);
|
||||||
|
|
||||||
|
var fileStream = File.OpenRead(filePath);
|
||||||
|
|
||||||
|
if (!metadata.TryReadFromStream(fileStream, Version))
|
||||||
|
{
|
||||||
|
decryptedMemoryStream.Close();
|
||||||
|
fileStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return fileStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.ComputeAndValidateHmacHash(fileStream);
|
||||||
|
|
||||||
|
using (var algorithm = metadata.GetCryptographyAlgorithm())
|
||||||
|
{
|
||||||
|
using (var transform = algorithm.CreateDecryptor())
|
||||||
|
{
|
||||||
|
using (var cryptoStream = new CryptoStreamWrapper(fileStream, transform, CryptoStreamMode.Read))
|
||||||
|
{
|
||||||
|
cryptoStream.CopyTo(decryptedMemoryStream);
|
||||||
|
cryptoStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.Close();
|
||||||
|
|
||||||
|
decryptedMemoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return decryptedMemoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream GetReadStream(string filePath, string password)
|
||||||
|
{
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(password);
|
||||||
|
|
||||||
|
var fileStream = File.OpenRead(filePath);
|
||||||
|
|
||||||
|
if (!metadata.TryReadFromStream(fileStream, Version))
|
||||||
|
{
|
||||||
|
fileStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return fileStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.ComputeAndValidateHmacHash(fileStream);
|
||||||
|
|
||||||
|
var wrapper = new StreamWrapper(fileStream, metadata);
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long GetFileSize(string filePath, string password)
|
||||||
|
{
|
||||||
|
var metadata = EncryptionFactory.GetMetadata();
|
||||||
|
|
||||||
|
metadata.Initialize(password);
|
||||||
|
|
||||||
|
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, metadata.GetMetadataLength(), FileOptions.SequentialScan))
|
||||||
|
{
|
||||||
|
if (metadata.TryReadFromStream(fileStream, Version))
|
||||||
|
{
|
||||||
|
return metadata.GetFileSize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new FileInfo(filePath).Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetUniqFileName(string filePath, string ext)
|
||||||
|
{
|
||||||
|
var dir = string.IsNullOrEmpty(TempDir) ? Path.GetDirectoryName(filePath) : TempDir;
|
||||||
|
var name = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
var result = Path.Combine(dir, string.Format("{0}_{1}{2}", Storage, name, ext));
|
||||||
|
var index = 1;
|
||||||
|
|
||||||
|
while (File.Exists(result))
|
||||||
|
{
|
||||||
|
result = Path.Combine(dir, string.Format("{0}_{1}({2}){3}", Storage, name, index++, ext));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReplaceFile(string modifiedFilePath, string originalFilePath)
|
||||||
|
{
|
||||||
|
var tempFilePath = GetUniqFileName(originalFilePath, ".tmp");
|
||||||
|
|
||||||
|
File.Move(originalFilePath, tempFilePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Move(modifiedFilePath, originalFilePath);
|
||||||
|
}
|
||||||
|
catch(Exception exception)
|
||||||
|
{
|
||||||
|
File.Move(tempFilePath, originalFilePath);
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (File.Exists(tempFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(tempFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
common/ASC.Data.Storage/Encryption/CryptoStreamWrapper.cs
Normal file
50
common/ASC.Data.Storage/Encryption/CryptoStreamWrapper.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
//https://stackoverflow.com/a/22072068
|
||||||
|
|
||||||
|
internal sealed class CryptoStreamWrapper : CryptoStream
|
||||||
|
{
|
||||||
|
private readonly Stream underlyingStream;
|
||||||
|
|
||||||
|
public CryptoStreamWrapper(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
|
||||||
|
: base(stream, transform, mode)
|
||||||
|
{
|
||||||
|
underlyingStream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
catch (CryptographicException)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
underlyingStream.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
common/ASC.Data.Storage/Encryption/EncryptionFactory.cs
Normal file
59
common/ASC.Data.Storage/Encryption/EncryptionFactory.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using ASC.Common;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public class EncryptionFactory
|
||||||
|
{
|
||||||
|
private IServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
|
public EncryptionFactory(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
ServiceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICrypt GetCrypt(string storageName, EncryptionSettings encryptionSettings)
|
||||||
|
{
|
||||||
|
var crypt = ServiceProvider.GetService<Crypt>();
|
||||||
|
crypt.Init(storageName, encryptionSettings);
|
||||||
|
return crypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMetadata GetMetadata()
|
||||||
|
{
|
||||||
|
return ServiceProvider.GetService<Metadata>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EncryptionFactoryExtension
|
||||||
|
{
|
||||||
|
public static DIHelper AddEncryptionFactoryService(this DIHelper services)
|
||||||
|
{
|
||||||
|
services.TryAddSingleton<EncryptionFactory>();
|
||||||
|
services.TryAddTransient<Crypt>();
|
||||||
|
services.TryAddTransient<Metadata>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
common/ASC.Data.Storage/Encryption/ICrypt.cs
Normal file
34
common/ASC.Data.Storage/Encryption/ICrypt.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public interface ICrypt
|
||||||
|
{
|
||||||
|
byte Version { get; }
|
||||||
|
|
||||||
|
void EncryptFile(string filePath);
|
||||||
|
|
||||||
|
void DecryptFile(string filePath);
|
||||||
|
|
||||||
|
Stream GetReadStream(string filePath);
|
||||||
|
|
||||||
|
long GetFileSize(string filePath);
|
||||||
|
}
|
||||||
|
}
|
45
common/ASC.Data.Storage/Encryption/IMetadata.cs
Normal file
45
common/ASC.Data.Storage/Encryption/IMetadata.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public interface IMetadata
|
||||||
|
{
|
||||||
|
void Initialize(string password);
|
||||||
|
|
||||||
|
void Initialize(byte version, string password, long fileSize);
|
||||||
|
|
||||||
|
bool TryReadFromStream(Stream stream, byte cryptVersion);
|
||||||
|
|
||||||
|
void WriteToStream(Stream stream);
|
||||||
|
|
||||||
|
SymmetricAlgorithm GetCryptographyAlgorithm();
|
||||||
|
|
||||||
|
void ComputeAndWriteHmacHash(Stream stream);
|
||||||
|
|
||||||
|
void ComputeAndValidateHmacHash(Stream stream);
|
||||||
|
|
||||||
|
byte GetCryptoVersion();
|
||||||
|
|
||||||
|
long GetFileSize();
|
||||||
|
|
||||||
|
int GetMetadataLength();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public class IntegrityProtectionException : Exception
|
||||||
|
{
|
||||||
|
public IntegrityProtectionException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegrityProtectionException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
311
common/ASC.Data.Storage/Encryption/Metadata.cs
Normal file
311
common/ASC.Data.Storage/Encryption/Metadata.cs
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
public class Metadata : IMetadata
|
||||||
|
{
|
||||||
|
private const string prefixString = "AscEncrypted";
|
||||||
|
|
||||||
|
private const int prefixLength = 12; // prefixString length
|
||||||
|
private const int versionLength = 1; // byte
|
||||||
|
private const int sizeLength = 8; // long (int64)
|
||||||
|
|
||||||
|
private const int saltLength = 32; // The salt size must be 8 bytes or larger
|
||||||
|
|
||||||
|
private const int keySize = 256; // key size, in bits, of the secret key used for the symmetric algorithm. AES-256
|
||||||
|
private const int blockSize = 128; // block size, in bits, of the cryptographic operation. default is 128 bits
|
||||||
|
|
||||||
|
private const int keyLength = keySize / 8; // secret key used for the symmetric algorithm. 32 bytes
|
||||||
|
private const int ivLength = blockSize / 8; // The initialization vector (IV) to use for the symmetric algorithm. 16 bytes
|
||||||
|
|
||||||
|
private const int hmacKeyLength = 64; // HMACSHA256 64-byte private key is recommended.
|
||||||
|
private const int hmacHashLength = 32; // HMACSHA256 The output hash is 256 bits (32 bytes) in length
|
||||||
|
|
||||||
|
private const int metadataLength = prefixLength + versionLength + sizeLength + saltLength + hmacHashLength + ivLength;
|
||||||
|
|
||||||
|
private static int? iterations; // Rfc2898DeriveBytes: The minimum recommended number of iterations is 1000.
|
||||||
|
|
||||||
|
private IConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
|
public Metadata(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int Iterations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (iterations.HasValue)
|
||||||
|
{
|
||||||
|
return iterations.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iterationsCount;
|
||||||
|
|
||||||
|
if (!int.TryParse(Configuration["storage:encryption:iterations"], out iterationsCount))
|
||||||
|
{
|
||||||
|
iterationsCount = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterations = iterationsCount;
|
||||||
|
|
||||||
|
return iterations.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Password;
|
||||||
|
|
||||||
|
private byte[] Prefix;
|
||||||
|
private byte[] Version;
|
||||||
|
private byte[] Size;
|
||||||
|
|
||||||
|
private byte[] Salt;
|
||||||
|
|
||||||
|
private byte[] Key;
|
||||||
|
private byte[] IV;
|
||||||
|
|
||||||
|
private byte[] HmacKey;
|
||||||
|
private byte[] HmacHash;
|
||||||
|
|
||||||
|
|
||||||
|
public void Initialize(string password)
|
||||||
|
{
|
||||||
|
Password = password;
|
||||||
|
|
||||||
|
Prefix = Encoding.UTF8.GetBytes(prefixString);
|
||||||
|
Version = new byte[versionLength];
|
||||||
|
Size = new byte[sizeLength];
|
||||||
|
|
||||||
|
Salt = new byte[saltLength];
|
||||||
|
|
||||||
|
Key = new byte[keyLength];
|
||||||
|
IV = new byte[ivLength];
|
||||||
|
|
||||||
|
HmacKey = new byte[hmacKeyLength];
|
||||||
|
HmacHash = new byte[hmacHashLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(byte version, string password, long fileSize)
|
||||||
|
{
|
||||||
|
Password = password;
|
||||||
|
|
||||||
|
Prefix = Encoding.UTF8.GetBytes(prefixString);
|
||||||
|
Version = new byte[versionLength] { version };
|
||||||
|
Size = LongToByteArray(fileSize);
|
||||||
|
|
||||||
|
Salt = GenerateRandom(saltLength);
|
||||||
|
|
||||||
|
Key = GenerateKey();
|
||||||
|
IV = GenerateRandom(ivLength);
|
||||||
|
|
||||||
|
HmacKey = GenerateHmacKey();
|
||||||
|
HmacHash = new byte[hmacHashLength]; // Empty byte array. The real hmac will be computed after encryption
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TryReadFromStream(Stream stream, byte cryptVersion)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var readed = stream.Read(Prefix, 0, prefixLength);
|
||||||
|
if (readed < prefixLength) return false;
|
||||||
|
|
||||||
|
if (Encoding.UTF8.GetString(Prefix) != prefixString) return false;
|
||||||
|
|
||||||
|
readed = stream.Read(Version, 0, versionLength);
|
||||||
|
if (readed < versionLength) return false;
|
||||||
|
|
||||||
|
if (Version[0] != cryptVersion) return false;
|
||||||
|
|
||||||
|
readed = stream.Read(Size, 0, sizeLength);
|
||||||
|
if (readed < sizeLength) return false;
|
||||||
|
|
||||||
|
if (ByteArrayToLong(Size) < 0) return false;
|
||||||
|
|
||||||
|
readed = stream.Read(Salt, 0, saltLength);
|
||||||
|
if (readed < saltLength) return false;
|
||||||
|
|
||||||
|
readed = stream.Read(HmacHash, 0, hmacHashLength);
|
||||||
|
if (readed < hmacHashLength) return false;
|
||||||
|
|
||||||
|
readed = stream.Read(IV, 0, ivLength);
|
||||||
|
if (readed < ivLength) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteToStream(Stream stream)
|
||||||
|
{
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
stream.Write(Prefix, 0, prefixLength);
|
||||||
|
stream.Write(Version, 0, versionLength);
|
||||||
|
stream.Write(Size, 0, sizeLength);
|
||||||
|
stream.Write(Salt, 0, saltLength);
|
||||||
|
stream.Write(HmacHash, 0, hmacHashLength);
|
||||||
|
stream.Write(IV, 0, ivLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymmetricAlgorithm GetCryptographyAlgorithm()
|
||||||
|
{
|
||||||
|
return new RijndaelManaged
|
||||||
|
{
|
||||||
|
KeySize = keySize,
|
||||||
|
BlockSize = blockSize,
|
||||||
|
Key = Key,
|
||||||
|
IV = IV,
|
||||||
|
Padding = PaddingMode.PKCS7,
|
||||||
|
Mode = CipherMode.CBC
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ComputeAndWriteHmacHash(Stream stream)
|
||||||
|
{
|
||||||
|
HmacHash = ComputeHmacHash(stream);
|
||||||
|
|
||||||
|
stream.Seek(metadataLength - ivLength - hmacHashLength, SeekOrigin.Begin); // Move position to hmac
|
||||||
|
|
||||||
|
stream.Write(HmacHash, 0, hmacHashLength); // Replace empty hmac with computed
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ComputeAndValidateHmacHash(Stream stream)
|
||||||
|
{
|
||||||
|
Key = GenerateKey();
|
||||||
|
|
||||||
|
HmacKey = GenerateHmacKey();
|
||||||
|
|
||||||
|
var computedHash = ComputeHmacHash(stream);
|
||||||
|
|
||||||
|
if (!HmacHash.SequenceEqual(computedHash))
|
||||||
|
{
|
||||||
|
stream.Close();
|
||||||
|
|
||||||
|
throw new IntegrityProtectionException("Invalid signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Seek(metadataLength, SeekOrigin.Begin); // Move position to encrypted data
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetCryptoVersion()
|
||||||
|
{
|
||||||
|
return Version[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GetFileSize()
|
||||||
|
{
|
||||||
|
return ByteArrayToLong(Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetMetadataLength()
|
||||||
|
{
|
||||||
|
return metadataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] GenerateRandom(int length)
|
||||||
|
{
|
||||||
|
var random = new byte[length];
|
||||||
|
|
||||||
|
using (var rng = new RNGCryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rng.GetBytes(random);
|
||||||
|
}
|
||||||
|
|
||||||
|
return random;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GenerateKey()
|
||||||
|
{
|
||||||
|
var key = new byte[keyLength];
|
||||||
|
|
||||||
|
using (var deriveBytes = new Rfc2898DeriveBytes(Password, Salt, Iterations, HashAlgorithmName.SHA256))
|
||||||
|
{
|
||||||
|
key = deriveBytes.GetBytes(keyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GenerateHmacKey()
|
||||||
|
{
|
||||||
|
var hmacKey = new byte[hmacKeyLength];
|
||||||
|
|
||||||
|
using (var sha512 = new SHA512Managed())
|
||||||
|
{
|
||||||
|
hmacKey = sha512.ComputeHash(Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hmacKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] ComputeHmacHash(Stream stream)
|
||||||
|
{
|
||||||
|
var hmacHash = new byte[hmacHashLength];
|
||||||
|
|
||||||
|
stream.Seek(metadataLength - ivLength, SeekOrigin.Begin); // Move position to (IV + encrypted data)
|
||||||
|
|
||||||
|
using (var hmac = new HMACSHA256(HmacKey))
|
||||||
|
{
|
||||||
|
hmacHash = hmac.ComputeHash(stream); // IV needs to be part of the MAC calculation
|
||||||
|
}
|
||||||
|
|
||||||
|
return hmacHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] LongToByteArray(long value)
|
||||||
|
{
|
||||||
|
var result = BitConverter.GetBytes(value);
|
||||||
|
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long ByteArrayToLong(byte[] value)
|
||||||
|
{
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(value);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return BitConverter.ToInt64(value, 0);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
common/ASC.Data.Storage/Encryption/StreamWrapper.cs
Normal file
110
common/ASC.Data.Storage/Encryption/StreamWrapper.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (c) Copyright Ascensio System Limited 2010-2020
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace ASC.Data.Storage.Encryption
|
||||||
|
{
|
||||||
|
internal sealed class StreamWrapper : Stream
|
||||||
|
{
|
||||||
|
private readonly Stream stream;
|
||||||
|
private readonly CryptoStream cryptoStream;
|
||||||
|
private readonly SymmetricAlgorithm symmetricAlgorithm;
|
||||||
|
private readonly ICryptoTransform cryptoTransform;
|
||||||
|
private readonly long fileSize;
|
||||||
|
private readonly long metadataLength;
|
||||||
|
|
||||||
|
public StreamWrapper(Stream fileStream, IMetadata metadata)
|
||||||
|
{
|
||||||
|
stream = fileStream;
|
||||||
|
symmetricAlgorithm = metadata.GetCryptographyAlgorithm();
|
||||||
|
cryptoTransform = symmetricAlgorithm.CreateDecryptor();
|
||||||
|
cryptoStream = new CryptoStreamWrapper(stream, cryptoTransform, CryptoStreamMode.Read);
|
||||||
|
fileSize = metadata.GetFileSize();
|
||||||
|
metadataLength = metadata.GetMetadataLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return stream.CanRead; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { return fileSize; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return stream.Position - metadataLength;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 0 || value > fileSize)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
stream.Position = value + metadataLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
return cryptoStream.Read(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
cryptoStream.Dispose();
|
||||||
|
stream.Dispose();
|
||||||
|
symmetricAlgorithm.Dispose();
|
||||||
|
cryptoTransform.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ using ASC.Core.Common.Configuration;
|
|||||||
using ASC.Core.Common.Settings;
|
using ASC.Core.Common.Settings;
|
||||||
using ASC.Data.Storage.Configuration;
|
using ASC.Data.Storage.Configuration;
|
||||||
using ASC.Data.Storage.DiscStorage;
|
using ASC.Data.Storage.DiscStorage;
|
||||||
|
using ASC.Data.Storage.Encryption;
|
||||||
using ASC.Security.Cryptography;
|
using ASC.Security.Cryptography;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -168,6 +169,8 @@ namespace ASC.Data.Storage
|
|||||||
private EmailValidationKeyProvider EmailValidationKeyProvider { get; }
|
private EmailValidationKeyProvider EmailValidationKeyProvider { get; }
|
||||||
private IOptionsMonitor<ILog> Options { get; }
|
private IOptionsMonitor<ILog> Options { get; }
|
||||||
private IHttpContextAccessor HttpContextAccessor { get; }
|
private IHttpContextAccessor HttpContextAccessor { get; }
|
||||||
|
private EncryptionSettingsHelper EncryptionSettingsHelper { get; }
|
||||||
|
private EncryptionFactory EncryptionFactory { get; }
|
||||||
|
|
||||||
public StorageFactory(
|
public StorageFactory(
|
||||||
StorageFactoryListener storageFactoryListener,
|
StorageFactoryListener storageFactoryListener,
|
||||||
@ -178,8 +181,10 @@ namespace ASC.Data.Storage
|
|||||||
CoreBaseSettings coreBaseSettings,
|
CoreBaseSettings coreBaseSettings,
|
||||||
PathUtils pathUtils,
|
PathUtils pathUtils,
|
||||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||||
IOptionsMonitor<ILog> options) :
|
IOptionsMonitor<ILog> options,
|
||||||
this(storageFactoryListener, storageFactoryConfig, settingsManager, storageSettingsHelper, tenantManager, coreBaseSettings, pathUtils, emailValidationKeyProvider, options, null)
|
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||||
|
EncryptionFactory encryptionFactory) :
|
||||||
|
this(storageFactoryListener, storageFactoryConfig, settingsManager, storageSettingsHelper, tenantManager, coreBaseSettings, pathUtils, emailValidationKeyProvider, options, null, encryptionSettingsHelper, encryptionFactory)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public StorageFactory(
|
public StorageFactory(
|
||||||
@ -192,7 +197,9 @@ namespace ASC.Data.Storage
|
|||||||
PathUtils pathUtils,
|
PathUtils pathUtils,
|
||||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||||
IOptionsMonitor<ILog> options,
|
IOptionsMonitor<ILog> options,
|
||||||
IHttpContextAccessor httpContextAccessor)
|
IHttpContextAccessor httpContextAccessor,
|
||||||
|
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||||
|
EncryptionFactory encryptionFactory)
|
||||||
{
|
{
|
||||||
StorageFactoryListener = storageFactoryListener;
|
StorageFactoryListener = storageFactoryListener;
|
||||||
StorageFactoryConfig = storageFactoryConfig;
|
StorageFactoryConfig = storageFactoryConfig;
|
||||||
@ -204,6 +211,8 @@ namespace ASC.Data.Storage
|
|||||||
EmailValidationKeyProvider = emailValidationKeyProvider;
|
EmailValidationKeyProvider = emailValidationKeyProvider;
|
||||||
Options = options;
|
Options = options;
|
||||||
HttpContextAccessor = httpContextAccessor;
|
HttpContextAccessor = httpContextAccessor;
|
||||||
|
EncryptionSettingsHelper = encryptionSettingsHelper;
|
||||||
|
EncryptionFactory = encryptionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDataStore GetStorage(string tenant, string module)
|
public IDataStore GetStorage(string tenant, string module)
|
||||||
@ -301,7 +310,7 @@ namespace ASC.Data.Storage
|
|||||||
props = handler.Property.ToDictionary(r => r.Name, r => r.Value);
|
props = handler.Property.ToDictionary(r => r.Name, r => r.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((IDataStore)Activator.CreateInstance(instanceType, TenantManager, PathUtils, EmailValidationKeyProvider, HttpContextAccessor, Options))
|
return ((IDataStore)Activator.CreateInstance(instanceType, TenantManager, PathUtils, EmailValidationKeyProvider, HttpContextAccessor, Options, EncryptionSettingsHelper, EncryptionFactory))
|
||||||
.Configure(tenant, handler, moduleElement, props)
|
.Configure(tenant, handler, moduleElement, props)
|
||||||
.SetQuotaController(moduleElement.Count ? controller : null
|
.SetQuotaController(moduleElement.Count ? controller : null
|
||||||
/*don't count quota if specified on module*/);
|
/*don't count quota if specified on module*/);
|
||||||
@ -331,7 +340,8 @@ namespace ASC.Data.Storage
|
|||||||
.AddPathUtilsService()
|
.AddPathUtilsService()
|
||||||
.AddEmailValidationKeyProviderService()
|
.AddEmailValidationKeyProviderService()
|
||||||
.AddStorageSettingsService()
|
.AddStorageSettingsService()
|
||||||
.AddStorage();
|
.AddStorage()
|
||||||
|
.AddEncryptionFactoryService();
|
||||||
}
|
}
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
|
@ -376,8 +376,8 @@ namespace ASC.Data.Storage.Encryption
|
|||||||
{
|
{
|
||||||
public static DIHelper AddEncryptionOperationService(this DIHelper services)
|
public static DIHelper AddEncryptionOperationService(this DIHelper services)
|
||||||
{
|
{
|
||||||
services.TryAddSingleton<EncryptionOperation>();
|
services.TryAddTransient<EncryptionOperation>();
|
||||||
services.TryAddScoped<EncryptionOperationScope>();
|
services.TryAddTransient<EncryptionOperationScope>();
|
||||||
return services
|
return services
|
||||||
.AddStorageFactoryConfigService()
|
.AddStorageFactoryConfigService()
|
||||||
.AddStorageFactoryService()
|
.AddStorageFactoryService()
|
||||||
|
@ -19,13 +19,6 @@ namespace ASC.Data.Storage.Encryption
|
|||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
StartEncryption(new EncryptionSettingsProto()
|
|
||||||
{
|
|
||||||
Password = "wda",
|
|
||||||
Status = EncryprtionStatus.EncryptionStarted,
|
|
||||||
NotifyUsers = true,
|
|
||||||
ServerRootPath = ""
|
|
||||||
});
|
|
||||||
NotifySettings.Subscribe((n) => StartEncryption(n), CacheNotifyAction.Insert);
|
NotifySettings.Subscribe((n) => StartEncryption(n), CacheNotifyAction.Insert);
|
||||||
NotifyStop.Subscribe((n) => StopEncryption(), CacheNotifyAction.Insert);
|
NotifyStop.Subscribe((n) => StopEncryption(), CacheNotifyAction.Insert);
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,8 @@
|
|||||||
},
|
},
|
||||||
"storage": {
|
"storage": {
|
||||||
"encryption": {
|
"encryption": {
|
||||||
"progressfile": "false"
|
"progressfile": "false",
|
||||||
|
"tempdir": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,8 @@
|
|||||||
"virtualpath": "~/products/files/docstore",
|
"virtualpath": "~/products/files/docstore",
|
||||||
"appendTenantId": false,
|
"appendTenantId": false,
|
||||||
"public": true,
|
"public": true,
|
||||||
"disableMigrate": true
|
"disableMigrate": true,
|
||||||
|
"disableEncryption": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "crm",
|
"name": "crm",
|
||||||
@ -113,7 +114,8 @@
|
|||||||
"data": "00000000-0000-0000-0000-000000000000",
|
"data": "00000000-0000-0000-0000-000000000000",
|
||||||
"type": "disc",
|
"type": "disc",
|
||||||
"path": "Products\\CRM\\DocStore",
|
"path": "Products\\CRM\\DocStore",
|
||||||
"disableMigrate": true
|
"disableMigrate": true,
|
||||||
|
"disableEncryption": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fckuploaders",
|
"name": "fckuploaders",
|
||||||
@ -191,7 +193,8 @@
|
|||||||
"visible": "false",
|
"visible": "false",
|
||||||
"type": "disc",
|
"type": "disc",
|
||||||
"path": "$STORAGE_ROOT\\certs\\",
|
"path": "$STORAGE_ROOT\\certs\\",
|
||||||
"appendTenantId": false
|
"appendTenantId": false,
|
||||||
|
"disableEncryption": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mailaggregator",
|
"name": "mailaggregator",
|
||||||
@ -222,7 +225,8 @@
|
|||||||
"type": "disc",
|
"type": "disc",
|
||||||
"path": "$STORAGE_ROOT\\Studio\\{0}\\backup",
|
"path": "$STORAGE_ROOT\\Studio\\{0}\\backup",
|
||||||
"virtualpath": "~/studio/{0}/backup",
|
"virtualpath": "~/studio/{0}/backup",
|
||||||
"expires": "0:10:0"
|
"expires": "0:10:0",
|
||||||
|
"disableEncryption": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "customnavigation",
|
"name": "customnavigation",
|
||||||
@ -256,7 +260,8 @@
|
|||||||
"virtualpath": "~/App_Data/static/partnerdata",
|
"virtualpath": "~/App_Data/static/partnerdata",
|
||||||
"appendTenantId": false,
|
"appendTenantId": false,
|
||||||
"public": true,
|
"public": true,
|
||||||
"disableMigrate": true
|
"disableMigrate": true,
|
||||||
|
"disableEncryption": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user