I need to encrypt (or at least digitally sign) a package of content that is sent from the SharePoint Online server, down to the browser, and then cross-site post (JSONP) the ecrypted content to another system that can decrypt (or validate the signature). My problem is that I haven't come up with a secure way to encrypt the contents when working within the confines of a sandboxed solution and SharePoint Online.
I actually don't need encryption, per-se. I just need to sign the package in such a way that this external system knows I signed it. So, when I mention "encryption" or "encryption key", I am also talking about signature keys (certs, I suppose).
I can think of a few ways to store the encryption key, but I'm not sure any of them are secure:
- Store the encryption key in the code. This is typically a no-no, but regular users should not have access to the code. Maybe with obfuscation and/or a different key per-client this would be an option.
- Store the encryption key in the content database. This allows the key to be configurable, but my code needs to access the key under the context of any user and since we cannot impersonate or elevate permissions in a sandboxed environment, anyone will be able to make a web service call to get this key if they know what they are doing.
- Use the Secure Store Service to store the key. I don't think the SSS is really meant for this since the key would be the same for every user.
- Somehow read in the machine key. Even if we can do this in a sandboxed environment, we probably won't know how to unencrypt this on the other end.
Any ideas? I can even do a combination of options if that helps.
The original verison of this was a Farm Solution that would not work in SharePoint Online. It created a custom ticket and stored the ticket and current user details in a hidden list. It elevated permissions in order to create the entry in the list (regular users could not directly add data to the list). The ticket was returned to the browser and cross-posted to another system anonymously. The other system would make a server-to-server web service call to redeem the ticket to get back the user information and finally provide a session to the user based on the user name found in the redeemed ticket data. The whole purpose is to provide SSO to allow the IFrames to work in our web part. This is only needed if the customer does not already have their own SSO and we only make the calls in the case where authentication is needed.
In SharePoint Online I cannot elevate permissions so spoofing is a concern. I was hoping to simplify the entire design by removing the step where the ticket is redeemed, thus removing the need to temporarily store user information in a custom list and removing the complexity of calling a custom web service. To do this I just need to encrypt/sign the user information so the other system trusts who it is. The problem, as I outlined further above, is preventing others from encrypting/signing their own packet with a different username.
Using another system like Azure would involve authenticating to it and having SSO or using the Secure Store Service (SSS) to authenticate. That may have to be our answer - that every user has to setup their username/password in SSS for SSO to work. Not the answer I was looking for as our non-sandboxed implementation does not require every user to do this and it also allows for an option where users can be generated automatically in the other system.
Even though I was concerned that I could not decrypt something encrypted with the machine key, I thought I would explore this further...
I found that there is a way in .NET to encrypt content based on the MachineKey, but that is based on a MachineKey class that is only available in .NET Framework v4. It is not available in SharePoint code directly. Yes, we could put code that does it in another web app, but that defeats the purpose and would not be allowed in SharePoint Online anyways.
I tried the reflection hack for MachineKey which can work in a farm solution, but does not work in a sandboxed solution (ConfigurationManager.GetSection() fails). Other methods like DPAPI require COM which is not allowed in sandboxed solutions (I haven't tested this, but have read it).