Abstract

Force.com allows administrators to define data that can be encrypted at the field level. This article will focus on methods for enforcing encryption from a developer angle.

Understanding Shield Platform Encryption

Before you start encrypting fields, you should have a familiarity with Shield Platform Encryption for Partners, Encryption Strategy for Partners and also Important Changes for Shield Platform Encryption in Summer'16

Prerequisites

In order to execute the below lines of code you will need to enable encryption on the Phone field of the contact.

  1. Go to Setup |Security Controls | Platform Encryption.
  2. Click Encrypt Fields.
  3. Click Edit.
  4. Select the checkbox Phone under Contact.
  5. Save.

Automatic Encryption Enforcement in Visualforce

When rendering Visualforce pages, the platform will automatically enforce Encryption when the developer references sObjects and sObject fields directly in the Visualforce page. For example, if a user without Encryption visibility to the Phone field of the Contact object was to view the below page, phone numbers would be automatically encrypted from the table.

<apex:page standardController="Account">
 <apex:pageBlock title="Contacts">
   <apex:dataTable value="{!account.Contacts}" var="contact" cellPadding="4" border="1">
     <apex:column>
       <apex:facet name="header">Name</apex:facet>
       {!contact.Name}
     </apex:column>
     <apex:column>
       <apex:facet name="header">Phone</apex:facet>
       {!contact.Phone}
     </apex:column>
   </apex:dataTable>
 </apex:pageBlock>
</apex:page>

Contacts.jpg

Manual Encryption Enforcement in Apex Controllers

Encryption Access

There are often cases where developers use Visualforce to display data derived from an SObject field in an indirect or processed form. For instance, a page controller may use internal logic to determine the appropriate value to display. A simple example of this would be a page that displays a random SObject Name field from a list of SObjects:

<apex:page controller="RandomContactController">
 <apex:outputText value="{!RandomPhone}" />
</apex:page>

... and its corresponding Apex controller:

public with sharing class RandomContactController {

   public String getRandomPhone() {
       // Check if the Contact.Phone is encrypted for the current user and if the Current User has not VAD enabled
       if (Schema.sObjectType.Contact.fields.Phone.isEncrypted() && isNotVAD(UserInfo.getUserId())){
         return 'This field is encrypted';
       }
      
       Contact [] myList = [SELECT phone FROM Contact LIMIT 1000];
       // Pick a list entry at random
       Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size());
       Contact selected = myList.get(index);
       return selected.Phone;
   }
   
   Private boolean isNotVAD(ID userid){
       // check for user Profile if it has VAD enabled
       id pID = UserInfo.getProfileID();
       Boolean isVAD = [select PermissionsViewEncryptedData from Profile where ID =: pID].PermissionsViewEncryptedData;
       if (isVAd) {
           return false;
       }
       // check all Permisssion Sets and check if any has VAD enabled
       list<id> psIDs= new list<id>();
       for (PermissionSetAssignment psa : [SELECT PermissionSetId FROM PermissionSetAssignment where AssigneeId =:userid]){
           psIDs.add(psa.PermissionSetId);
       }
       for (permissionset ps : [select PermissionsViewEncryptedData from PermissionSet where id in:psIDs]){
           if (ps.PermissionsViewEncryptedData) {
               return false;
           }
       }
       return true;
   }
}

Encrypt.jpg

The above example indirectly displays the Phone field of the Contact object by using a customer getter method that returns a string value. Because Visualforce only sees the return value as a string and not as an SObject field, Encryption is not automatically enforced and it is necessary to call isEncrypted() on the appropriate Describe Field Result but also check if the user has not View Encryption Data (aka VAD) enabled in order to manually check the user's Encryption access.

Manual Encryption Enforcement in Visualforce

The field describe calls available in Apex are also available in Visualforce through the $ObjectType element. While enforcement in Apex controllers is preferred for scalability and general robustness reasons, there are situations where manual enforcement in Visualforce is useful. This will not check if the current user has View Encrypted Data enabled.

<!-- This would normally bypass automatic FLS enforcement for accessibility-->
<apex:outputText value="{!contactPhone}"
            rendered="{!not($ObjectType.Contact.fields.Phone.Encrypted)}" />

Encryption Enforcement in Apex Web Services

Since Apex web services do not have a Visualforce binding layer, all Encryption enforcement must be done within the Apex code. global with sharing class ContactWebService {

 webservice static String getContactPhone (Id contactId) {
   // Check if the user has encryption access on the Phone field
   if (!Schema.sObjectType.Contact.fields.Phone.isEncrypted() && isNotVAD(UserInfo.getUserId()){
     return null;
   }
   return [SELECT Phone FROM Contact WHERE            
           Id=:contactId].Phone;                                                      
 } 
Private boolean isNotVAD(ID userid){
       // check The profile
       id pID = UserInfo.getProfileID();
       Boolean isVAD = [select PermissionsViewEncryptedData from Profile where ID =: pID].PermissionsViewEncryptedData;
       if (isVAd) {
           return false;
       }
       // check all Permisssion Sets
       list<id> psIDs= new list<id>();
       for (PermissionSetAssignment psa : [SELECT PermissionSetId FROM PermissionSetAssignment where AssigneeId =:userid]){
           psIDs.add(psa.PermissionSetId);
       }
       for (permissionset ps : [select PermissionsViewEncryptedData from PermissionSet where id in:psIDs]){
           if (ps.PermissionsViewEncryptedData) {
               return false;
           }
       }
       return true;
   }
}

References