Secure InfoPath forms in SharePoint using encryption
Learn how you can use encryption and decryption to secure and protect data stored in InfoPath forms that are displayed through a browser via SharePoint.
Problem
You've got an InfoPath browser form in SharePoint in which sensitive information such as personal information or credit card numbers are stored.
You want to be able to restrict the viewing of this information only to people who have been authorized to view protected sensitive data in an InfoPath browser form within SharePoint (demo video).
Solution
Use encryption to encrypt and decrypt sensitive data that is stored in fields on an InfoPath browser form in SharePoint.
Before you begin
This article assumes that you have already mastered the InfoPath basics, know how to add conditional formatting to InfoPath controls, and know how to write and add code to an InfoPath form template.
Discussion
InfoPath forms are self-contained, meaning that the data is stored within the form itself and not in an external data store such as a database. When dealing with SharePoint, the XML of InfoPath forms is eventually stored in a SharePoint content database, but still each InfoPath form remains an XML file that contains all of its own data.
Because InfoPath forms store their own data, you need to come up with a clever way to encrypt and decrypt the data when the form is closed and opened.
The trick to using encryption to protect and secure data in InfoPath forms is to encrypt the data and empty all of the fields that contain sensitive data before the form is saved. And then when the form is opened, decrypt the data and populate the fields again with the sensitive data.
You can achieve this functionality as follows:
- In InfoPath, create a browser-compatible form template that resembles the following figure.
Figure 1. Browser-compatible InfoPath form template with security features.
- The Main data source of the InfoPath form template should resemble the following figure.
Figure 2. Main data source of the secure InfoPath form template.
Description of the purpose of each node in the main data source of the secure InfoPath form template:
- The password node is used for the user to enter a password. This field is always cleared after the user presses the Protect or Unprotect button to prevent the password from being stored in the form when the form is saved.
- The isLocked node is used to keep track of whether the data in the InfoPath form is secured or not. This is a hidden field in the InfoPath form and is used to enable/disable the Protect and Unprotect buttons through conditional formatting.
- The encryptedData node is used for storing the encrypted data of all of the protected fields. This is also a hidden field.
- The emptyProtectedFields node is used to store the XML structure of all of the fields under the protectedFields group node. This data will be used to quickly empty all of the protected fields. This field is also a hidden field.
- The protectedFields group node contains the fields that are shown on the InfoPath form and that should be secured.
- The errorMessage node is used for displaying messages to the user. An Expression Box is used to display this field on the InfoPath form.
Add the following Conditional Formatting to the Protect button:
If this condition is true:
isLocked is not blankThen apply this formatting:
Disable this controlAdd the following Conditional Formatting to the Unprotect button:
If this condition is true:
isLocked is blankThen apply this formatting:
Disable this controlAdd the following using statements to the InfoPath form code file:
using System.Text;
using System.IO;
using System.Security.Cryptography;- Download the code to implement encryption, copy the methods from the file, and add them to the InfoPath form code file.
Add the following code to the Loading event handler of the InfoPath form template:
try
{
XPathNavigator root = MainDataSource.CreateNavigator();
// Copy the XML structure for the protectedFields node with empty values
string emptyProtectedFields = root.SelectSingleNode(
"/my:myFields/my:protectedFields", NamespaceManager).OuterXml;
// Store the XML structure in the emptyProtectedFields node
root.SelectSingleNode("/my:myFields/my:emptyProtectedFields",
NamespaceManager).SetValue(emptyProtectedFields);
}
catch (Exception ex)
{
SetErrorMessage(ex.Message);
}
Add the following code to the Clicked event handler of the Protect button:
try
{
ClearErrorMessage();
XPathNavigator root = MainDataSource.CreateNavigator();
// Generate the encryption key using the password
string password = root.SelectSingleNode(
"/my:myFields/my:password", NamespaceManager).Value;
SymmetricAlgorithm symmKey = GenerateKey(password);
// Retrieve and encrypt the sensitive fields
string dataToEncrypt = root.SelectSingleNode(
"/my:myFields/my:protectedFields", NamespaceManager).OuterXml;
root.SelectSingleNode("/my:myFields/my:encryptedData",
NamespaceManager).SetValue(EncryptField(symmKey, dataToEncrypt));
// Encrypt the isLocked field
root.SelectSingleNode("/my:myFields/my:isLocked",
NamespaceManager).SetValue(EncryptField(symmKey, "locked"));
// Do not save the password; empty the password field
root.SelectSingleNode("/my:myFields/my:password",
NamespaceManager).SetValue(String.Empty);
// Empty the protected fields node
string emptyProtectedFields = root.SelectSingleNode(
"/my:myFields/my:emptyProtectedFields", NamespaceManager).Value;
XPathNavigator container = root.SelectSingleNode(
"//my:protectedFields", NamespaceManager);
container.ReplaceSelf(emptyProtectedFields);
}
catch (Exception ex)
{
SetErrorMessage(ex.Message);
}
Add the following code to the Clicked event handler of the Unprotect button:
try
{
ClearErrorMessage();
XPathNavigator root = MainDataSource.CreateNavigator();
// Retrieve the password entered by the user and generate a key
string password = root.SelectSingleNode("/my:myFields/my:password",
NamespaceManager).Value;
SymmetricAlgorithm symmKey = GenerateKey(password);
// Retrieve the encrypted data
string encryptedData = root.SelectSingleNode(
"/my:myFields/my:encryptedData", NamespaceManager).Value;
// Try to decrypt the data
string decryptedData = DecryptField(symmKey, encryptedData);
// Put the decrypted data in the protectedFields node
XPathNavigator container = root.SelectSingleNode(
"//my:protectedFields", NamespaceManager);
container.ReplaceSelf(decryptedData);
// Empty the isLocked and password fields
root.SelectSingleNode("/my:myFields/my:isLocked",
NamespaceManager).SetValue(String.Empty);
root.SelectSingleNode("/my:myFields/my:password",
NamespaceManager).SetValue(String.Empty);
}
catch (CryptographicException)
{
string msg = "Either the password you entered is incorrect ";
msg += "or you are not authorized to view the protected data.";
SetErrorMessage(msg);
}
catch (Exception)
{
string msg = "The InfoPath form has been tampered with; ";
msg += "cannot unprotect the data.";
SetErrorMessage(msg);
}
- Save the InfoPath form template and build the project.
- Deploy the InfoPath form template with C# code to SharePoint using an administrator-approved deployment.
You should now have a fully functional InfoPath form that displays the behavior shown in this Password-protect InfoPath browser forms in SharePoint demo video.
Note: The solution described in this article prevents everybody who is not the first person who clicks on the Protect button to secure the InfoPath form from viewing the sensitive data contained within the form. If you want to authorize a select group of people to view the secure data, you can make use of a saltValue that is an empty string (or a string that does not change) instead of the user name of the person who protects the form, and then share this password among the members of the group.
Related InfoPath Articles:
