locked
How can I extend Azure Storage Model to Automatically Encrypt or do a Cryptographic Hash? RRS feed

  • Question

  • I am looking at storing data in Azure Table where the presence of a public key hash in a PK/RK entry will result in permission being granted to the user.  

    How can I hook into the storage client library so that my cryptographic hash is generated upon serialization, and validated upon de serialization.  I don't need help with the crypto code... just how do I hook into the client while maintaining a smooth user experience.

    I may modify this behavior to also encrypt certain properties.

    Lastly I intend to store the results of this validation in a non-serialized property/enum.

     

    I'd be interested in tips for both Blob and Table 


    Tuesday, April 26, 2011 2:20 AM

Answers

All replies

  • For blobs the Storage client deals with the raw bytes / contents. As such you can do whatever you like to the data before you send it and after retrieving it. For additional convenience you could construct a simple extension method that would encrypt the data & upload it,

    i.e.

    public static class MySecureBlobExtensions
    {
       public static void EncryptedUpload(this CloudBlob blobref, byte[] data)
       {
            byte[] encryptedData = Encrypt(data);
            blobref.UploadByteArray(encryptedData);
       }

       public static byte[] DecyptedDownload(this CloudBlob blobref, byte[] data)
       {
             byte[] encryptedData = blobref.DownloadByteArray();
             return Decrypt(encryptedData);
       }
    }


    For Table entities there are two main approaches, the first is a bit advanced while the second is much more streamlined.


    1. You can make use of the DataServiceContext. ReadingEntity / WritingEntity events to do custom serialization / deserialization. You would need to hook up this event on any DataServiceContext that you would be using to access the entities in the future. The drawback here is that you would need to do custom xml parsing which may become tedious, essentially this gives you access to the raw XML data returned from the service as well as the entity it has deserialized.


    For example:


    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
    TableServiceContext ctx = tableClient.GetDataServiceContext();
    ctx.ReadingEntity += new <ReadingWritingEntityEventArgs>(OnReadingEntity);
    ctx.WritingEntity+=new EventHandler<ReadingWritingEntityEventArgs>(OnWritingEntity);

    public static void OnReadingEntity(object sender, ReadingWritingEntityEventArgs args)
    {
          XNamespaceAtomNamespace = "http://www.w3.org/2005/Atom";       
          XNamespaceAstoriaDataNamespace = http://schemas.microsoft.com/ado/2007/08/dataservices";   
          XElement entryNode = args.Data;
          MyEntityTypeworkItem = (MyEntityType)args.Entity;   
          // do decryption here  
         // If you need access to the raw xml this statement will get the properties element for you
          XElement propertiesElement = entryNode.Elements(AtomNamespace + "content").Elements(AstoriaMetadataNamespace + "properties").FirstOrDefault();
    }


     
    2. A more simple approach would be to simply define an entity with multiple properties and do not serialize the plain text versions. This can be achieved by either using a public getter method (non property), or a internal property which will be ignored by ADO.Net. A similar strategy can be used for storing the results of the validation as you mentioned above, however you could throw an exception in the property setters themselves.


    [DataServiceKey("PartitionKey", "RowKey")]

    public class MyEntityType
    {
         public string PartitionKey
         {
           get
           {
              // do encryption here
              return Encrypt(this.plainTextPartitionKey);
           }
           set
           {
              // do decryption here
              this.plainTextPartitionKey = Decrypt(value);
           }
         }

         public string RowKey
         {
           get
           {
               // do encryption here
               return Encrypt(this.plainTextRowKey);
           }
           set
           {
               // do decryption here
               this.plainTextRowKey = Decrypt(value);
           }
         }

         private string plainTextRowKey;

         private string plainTextPartitionKey;

     
        // Internal properties will not be serialized
        internal string PlainTextPK
         {
          get
          {
            return this.plainTextPartitionKey;
           }
          set
          {
            this.plainTextPartitionKey = value;
          }
        }

         internal string PlainTextRK
         {
           get
           {
             return this.plainTextRowKey;
           }
           set
           {
           this.plainTextRowKey = value;
           }
         }
    }

    Further work can be done combining the events mentioned above and a custom attribute that would allow you to mark a property as Ignored, but for your scenario this may not make sense. (see http://blogs.msdn.com/b/phaniraj/archive/2008/12/11/customizing-serialization-of-entities-in-the-ado-net-data-services-client-library.aspx)

     

    Hope this helps,

    Joe Giardino





    • Marked as answer by ChrisLaMont Wednesday, April 27, 2011 1:05 AM
    • Unmarked as answer by ChrisLaMont Thursday, May 12, 2011 9:45 PM
    Tuesday, April 26, 2011 7:43 PM
  • Just noticed you're a MSFT employee... It would be nice if this feature was included in the regular StorageClient.  You have the connections to make it happen?
    Wednesday, April 27, 2011 1:33 AM
  • The "advanced" approach seems interesting and seamless, and I'd like to put it on codeplex.  I've already published a starter codeplex project, and solicited the security community's feedback on my code.

    http://social.msdn.microsoft.com/Forums/en-US/windowsazuresecurity/thread/07510876-40a1-4363-ac83-b7f6e3f2fc89

     

    Joe - Can you give me a little more insight on how to parse the XML?  I'd like to encrypt the values and possibly the property names as well.  Any guidance would be appreciated.



    Wednesday, May 11, 2011 9:51 PM
  • Chris -

    I did a post on entities in Azure Table which has a longer discussion of the ReadingEntity and WritingEntity events - and which contains some XML querying.

    • Marked as answer by ChrisLaMont Wednesday, May 11, 2011 11:35 PM
    • Unmarked as answer by ChrisLaMont Thursday, May 12, 2011 9:45 PM
    Wednesday, May 11, 2011 10:02 PM
    Answerer
  • Thanks Neil...Here is a project that is inspired by your link. http://azuretableencrypt.codeplex.com/

    It will automatically encrypt/decrypt Entities on the fly.  

    • Marked as answer by ChrisLaMont Thursday, May 12, 2011 9:43 PM
    Thursday, May 12, 2011 5:27 AM