Загрузка зашифрованного файла из хранилища Windows Azure

Я создал приложение Azure MVC WebRole Window, в котором я загружаю зашифрованные файлы в хранилище BLOB-объектов Azure, используя SymmetricAlgorithm (Rijndael), как это

Контроллер>Действие

[HttpPost]
public ActionResult UploadImage_post(HttpPostedFileBase fileBase)
{
    if (fileBase.ContentLength > 0)
    {
       // Retrieve a reference to a container 
       Microsoft.WindowsAzure.StorageClient.CloudBlobContainer blobContainer =
              _myBlobStorageService.GetCloudBlobContainer();

       Microsoft.WindowsAzure.StorageClient.CloudBlob blob =
                blobContainer.GetBlobReference(fileBase.FileName);
       using (BlobStream blobStream = blob.OpenWrite())
       {
             string encryptionKey = //somekey;
             byte[] file = new byte[fileBase.ContentLength];
             EncDecAlgo.EncryptBlobFile(file, blobStream, encryptionKey);
       }
    }
}

public void EncryptBlobFile(byte[] file, BlobStream bs, string key)
    {
        PasswordDeriveBytes pdb = new PasswordDeriveBytes(key,
            new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 
        0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
        Rijndael alg = Rijndael.Create();

        alg.Key = pdb.GetBytes(32);
        alg.IV = pdb.GetBytes(16);

        CryptoStream cs = new CryptoStream(bs,
           alg.CreateEncryptor(), CryptoStreamMode.Write);

        foreach (var data in file)
        {
            cs.WriteByte((byte)data);
        }

        cs.Close();
        bs.Close();
    }

Приведенное выше шифрование файлов работает нормально.

Код для загрузки

 public ActionResult DownloadFile(string filename)
    {
        // Retrieve reference to a previously created container.
        Microsoft.WindowsAzure.StorageClient.CloudBlobContainer blobContainer =
         _myBlobStorageService.GetCloudBlobContainer();

        Microsoft.WindowsAzure.StorageClient.CloudBlob blob =
            blobContainer.GetBlobReference(filename);
        blob.FetchAttributes();
        string encryptionKey = //same key used in encryption;
        using (BlobStream blobStream = blob.OpenRead())
        {
            EncDecAlgo.DecryptBlobFile(blobStream, encryptionKey, filename);
        }
    }

    public static void DecryptBlobFile(BlobStream bs, string key, string filePath)
    {
        try
        {
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(key,
                new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 
        0x64, 0x76, 0x65, 0x64, 0x65, 0x76});

        Rijndael alg = Rijndael.Create();

        alg.Key = pdb.GetBytes(32);
        alg.IV =  pdb.GetBytes(16);

        CryptoStream cs = new CryptoStream(bs,
            alg.CreateDecryptor(), CryptoStreamMode.Read);

        // Decrypt & Download Here
        System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(filePath));
        System.Web.HttpContext.Current.Response.ContentType = "application/" + Path.GetExtension(filePath).Replace(".", "");


        int data;
        while ((data = cs.ReadByte()) != -1)
        {
            if (data != 0)
            {
            }
            System.Web.HttpContext.Current.Response.OutputStream.WriteByte((byte)data);
            System.Web.HttpContext.Current.Response.Flush();

        }
        cs.Close();
        bs.Close();
        }
        catch
        {
        }
    }

При загрузке получаю следующую ошибку

Server cannot set content type after HTTP headers have been sent.

Пожалуйста, предложите какое-нибудь решение.


person Anil D    schedule 19.05.2014    source источник
comment
Вы можете попробовать подделать тип файла. Если это файл myReport.pdf, переименуйте его в myReportpdf.txt. Я делаю что-то подобное с приложением, извлекающим файл отчетов Crystal Reports .rpt. мы переименовываем его в почтовый индекс, когда мы размещаем его на веб-сайте.   -  person dave k    schedule 19.05.2014
comment
@davek, изменив расширение файла, не открывает его как текстовый файл вместо pdf? и не работает..   -  person Anil D    schedule 19.05.2014
comment
Привет, @davek, на самом деле файл не загружается, и я получаю сообщение об ошибке. Сервер не может установить тип контента после отправки заголовков HTTP. Я отредактировал свой вопрос.   -  person Anil D    schedule 19.05.2014
comment
Извините, я думал, что вы изначально смогли загрузить файл типа txt. Загрузка работает?   -  person dave k    schedule 20.05.2014
comment
да загрузка работает нормально..   -  person Anil D    schedule 20.05.2014
comment
Перейдите по этой ссылке: code.msdn.microsoft.com /windowsazure/ . У них процесс загрузки немного отличается от вашего. Попробуйте сначала скачать его, не расшифровывая файл.   -  person dave k    schedule 20.05.2014
comment
я использовал этот код и отлично работает, но не уверен, как использовать его с шифрованием/дешифрованием..   -  person Anil D    schedule 20.05.2014


Ответы (1)


Это должно быть довольно просто, надеюсь, этого достаточно, чтобы вы начали:

public class CloudFileResult : ActionResult
{
  private string m_FileName;
  private CloudBlobContainer m_Container;

  public CloudFileResult(string imageName, CloudBlobContainer container)
  {
    if (string.IsNullOrEmpty(imageName))
    {
      throw new ArgumentNullException("imageName");
    }
    if (container == null)
    {
      throw new ArgumentNullException("container");
    }

    m_FileName = imageName;
    m_Container = container;
  }

  public override void ExecuteResult(ControllerContext context)
  {
    context.HttpContext.Response.Clear();
    var blockBlob = m_Container.GetBlockBlobReference(m_FileName);
    blockBlob.FetchAttributes();
    context.HttpContext.Response.ContentType = blockBlob.Metadata["ContentType"];
    const string key = "my secret";
    using (var pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }))
    {
      using (var alg = RijndaelManaged.Create())
      {
        alg.Key = pdb.GetBytes(32);
        alg.IV = pdb.GetBytes(16);
        using (var stream = new CryptoStream(context.HttpContext.Response.OutputStream, alg.CreateDecryptor(), CryptoStreamMode.Write))
        {
          blockBlob.DownloadToStream(stream);
        }
      }
    }
  }
}

static void UploadFileToCloud(CloudBlobContainer container, HttpPostedFileBase file)
{
  const string key = "my secret";
  using (var pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }))
  {
    using (var alg = RijndaelManaged.Create())
    {
      alg.Key = pdb.GetBytes(32);
      alg.IV = pdb.GetBytes(16);

      var blockBlob = container.GetBlockBlobReference(file.FileName);
      using (var stream = new CryptoStream(file.InputStream, alg.CreateEncryptor(), CryptoStreamMode.Read))
      {
        blockBlob.UploadFromStream(stream);
      }
      blockBlob.Metadata.Add("ContentType", file.ContentType);
      blockBlob.SetMetadata();
    }
  }
}

static CloudBlobContainer GetContainer()
{
  string connection = "DefaultEndpointsProtocol=http;AccountName=AzureAccount;AccountKey=AzureAccountKey;";
  var account = CloudStorageAccount.Parse(connection);
  var client = account.CreateCloudBlobClient();
  var container = client.GetContainerReference("container");
  return container;
}

Что касается загрузки, вы можете просто использовать:

[HttpGet]
public ActionResult Index(string fileName)
{
  if (!string.IsNullOrEmpty(fileName))
  {
    return new CloudFileResult(fileName, GetContainer());
  }
  return View();
}

Указатели:

  • Я предпочитаю использовать управляемые криптоалгоритмы
  • Я сохраняю тип содержимого исходного файла в метаданных большого двоичного объекта (чтобы вы знали, как его обслуживать)
  • catch {} вызывает у меня мурашки, по крайней мере, зарегистрируйте исключение где-нибудь
  • Вместо того, чтобы играть с HttpContext.Response, создайте собственный ActionResult
  • Всегда утилизируйте IDisposable stuff
person Ondrej Svejdar    schedule 30.05.2014
comment
На всякий случай, если это кому-то поможет, я продолжал сталкиваться с ужасной ошибкой: stackoverflow.com/questions/8583112/. Я добавил следующую строку: alg.Padding = System.Security.Cryptography.PaddingMode.PKCS7; перед строкой alg.Key, и это исправило это. - person Adrian Carr; 05.08.2014
comment
Привет, ребята, есть ли полезная ссылка, чтобы сделать это в ядре .Net? - person Neel; 06.08.2019