You are using an older browser that might negatively affect how this site is displayed. Please update to a modern browser to have a better experience. Sorry for the inconvenience!

Encrypt and Decrypt Data using Apex Crypto Class


Apex gives the flexibility to write our own cryptographic functions for ensuring the integrity of our data. Apex provides the Crypto class to protect our data from eavesdroppers.

Crypto class: 

Crypto class provides the following functions to encrypt and decrypt data:

  1. encrypt()
  1. decrypt()
  1. encryptWithManagedIV()
  1. decryptWithManagedIV()

These functions are using AES algorithm to generate the private key and these functions are using AES128, AES256, AES192 algorithms to encrypt and decrypt information. The AES algorithm requires initialization vector to encrypt and decrypt data. AES stands for Advanced Encryption Standard algorithm

encrypt() 

  1. If we want to specify our own initialization vector, we can use this method to encrypt our data.
  1. Syntax: encrypt(algorithmName, privateKey, initializationVector, clearText)
  1. This method returns the blob value. We can convert the encrypted blob value to string using encodingUtill.base64Encode(inputBlob)

decrypt() 

  1. This method is used to decrypt the blob cipher text using the specified algorithm, private key and initialization vector.
  1. Syntax: decrypt(algorithmName, privateKey, initializationVector, cipherText)
  1. This method returns the blob value. We can convert the decrypted blob value to string using blob.toString() method.

encryptWithManagedIV() 

  1. This method is used to encrypt the data with specified algorithm and private key. In this method, Salesforce automatically generate the initialization vector.
  1. The initialization vector is stored as first 128 bits (16 bytes) of the encrypted blob.
  1. Syntax: encryptWithManagedIV(algorithmName, privateKey, clearText)
  1. This method returns the blob value. The private key and clear text should be in the type of blob

decryptWithManagedIV() 

  1. This method is used to decrypt the blob IVAndCipherText using the specified algorithm and private key.
  1. In this method, we just pass the encrypted data to decrypt. The first 128 bits(16 bytes) of data must contain initialization vector.
  1. Syntax: decryptWithManagedIV(algorithmName, privateKey, IVAndCipherText)
  1. Return type of this method is blob. The private key and data to decrypt should be in the type of blob.

Example: 

In this example, I have used the trigger, helper class, VF page, and Extensions. In this example, I have used one custom object named Financial System. In this object, there is an Account number field. In below code, I have encrypted the data in account number field. Whenever a new record is created with an account number, then the private key of that cipher text will be sent to the logged in user’s email. I have placed one custom button called “Decrypt Data” in object detail page to view the original content of that account number field. If you enter the wrong private key, then it will show the error message.

Trigger: 

trigger FinancialSystem on Financial_System__c (After insert) { 

    EncryptAndDecryptHelper.processData(Trigger.new); 

} 

Helper Class: 

public class EncryptAndDecryptHelper { 

    public static Blob cryptoKey; 

    public static Map<Id,String> encryptKey = new Map<Id,String>(); 

    public static string expMsg; 

    public static void processData(List<Financial_System__c> newRecords){ 

        List<messaging.SingleEmailMessage> mailmsg = new List<messaging.SingleEmailMessage>(); 

        List<Financial_System__c> financeList = new List<Financial_System__c>(); 

        Set<Id> recIds = new Set<Id>(); 

        if(trigger.isAfter && trigger.isInsert){ 

            for(Financial_System__c financeRec : newRecords){ 

                if(financeRec.Account_Number__c != null){ 

                    recIds.add(financeRec.Id); 

                } 

            } 

            for(Financial_System__c financeRec : [SELECT Id,Account_Number__c FROM Financial_System__c WHERE Id IN: recIds]){ 

                financeRec.Account_Number__c = processEncryption(financeRec.Account_Number__c, financeRec.Id); 

                financeList.add(financeRec);        

                Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage(); 

                email.setToAddresses(new String[]{userInfo.getUserEmail()}); 

                email.setSubject('The Encryption Key'); 

                email.setPlainTextBody('Hi'+' '+userInfo.getName()+','+'\r\n\n'+ 'The key for your record:'+' '+ encryptKey.get(financeRec.Id) + '\r\n'+ 'The record Id is:' + ' '+ financeRec.Id); 

                mailmsg.add(email); 

            } 

            if(!financeList.isEmpty()){ 

                update financeList; 

            } 

            if(!mailmsg.isEmpty()){ 

                messaging.sendEmail(mailmsg);  

            } 

        }   

    } 

    public static string processEncryption(string name, Id recId){ 

        cryptoKey = Crypto.generateAesKey(128); 

        encryptKey.put(recId, EncodingUtil.base64Encode(cryptoKey)); 

        Blob data = Blob.valueOf(name); 

        Blob encryptedData = Crypto.encryptWithManagedIV('AES128', cryptoKey, data ); 

        string b64Data = EncodingUtil.base64Encode(encryptedData);  

        return b64Data; 

    } 

    public static String processDecryption(string encryptedData, String key){ 

        String decryptedData; 

        Blob data = EncodingUtil.base64Decode(encryptedData); 

        Blob privateKey = EncodingUtil.base64Decode(key);  

        try{ 

        Blob dataToDecrypt = Crypto.decryptWithManagedIV('AES128', privateKey, data); 

        decryptedData = dataToDecrypt.toString(); 

        } 

        catch(Exception e){ 

           expMsg = e.getMessage();  

        } 

        return (string.isEmpty(expMsg) ?  decryptedData :  null);  

    } 

} 

VF Page: 

<apex:page standardController="Financial_System__c" extensions="decryptExtension"> 

    <apex:form > 

        <apex:pageMessages /> 

        <apex:pageBlock title="Key Information"> 

            <apex:pageBlockSection > 

                <apex:inputText label="Enter your key" value="{!key}"/> 

            </apex:pageBlockSection> 

            <apex:pageBlockButtons > 

                <apex:commandButton value="Show" action="{!decryptData}"/> 

            </apex:pageBlockButtons> 

        </apex:pageBlock> 

    </apex:form>   

</apex:page> 

Extension Class: 

public class decryptExtension{ 

    public Financial_System__c rec{get;set;} 

    public string key{get;set;} 

    public id recordId{get;set;} 

    public decryptExtension(ApexPages.StandardController sc){ 

        recordId = Apexpages.CurrentPage().getParameters().get('id'); 

        if(recordId !=null){ 

            rec = [SELECT Id, Account_Number__c FROM Financial_System__c WHERE Id =: recordId ]; 

        } 

    } 

    public PageReference decryptData(){ 

        if(!string.isBlank(key)){ 

            String decryptedData = EncryptAndDecryptHelper.processDecryption(rec.Account_Number__c, key ); 

            if(decryptedData != null){  

                rec.Account_Number__c = decryptedData; 

                update rec; 

                PageReference pg = new PageReference('/'+rec.id); 

                return pg; 

            } 

            else{ 

                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error,'Invalid Key')); 

            } 

        } 

        else{ 

            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error,'Please enter your key')); 

        } 

        return null; 

    } 

}

 

Original Data: 

apex crypto

Encrypted Data: 

apex crypto

Note: In this encrypted data, first 16 bytes are initialization vector and the remaining are the encrypted form of original data.

Key Received: 

apex crypto

Decryption with invalid key:apex crypto

Decryption with valid Key:

apex crypto

Decrypted Data:

apex crypto

Considerations: 

  1. We can generate the private key using crypto.generateAESKey(Size) method or externally.
  1. The length of the private key must match to the specified algorithm: 128 bits, 192 bits or 256 bits.
  1. The private key should not be hardcoded in the apex code. Instead, it should be placed in a protected custom setting.
  1. The methods encrypt(), decrypt(), encryptWithManagedIV(), decryptWithManagedIV()only support blob as parameters except the algorithm name.

Reference: 

Apex crypto class