Encrypt and Decrypt Data using Apex Crypto Class

Share on facebook
Share on twitter
Share on linkedin
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. 

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()
  2. decrypt()
  3. encryptWithManagedIV()
  4. 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.
  2. Syntax: encrypt(algorithmName, privateKey, initializationVector, clearText)
  3. 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.
  2. Syntax: decrypt(algorithmName, privateKey, initializationVector, cipherText)
  3. 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.
  2. The initialization vector is stored as first 128 bits (16 bytes) of the encrypted blob.
  3. Syntax: encryptWithManagedIV
  4. (algorithmName, privateKey, clearText)
  5. 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.
  2. In this method, we just pass the encrypted data to decrypt. The first 128 bits(16 bytes) of data must contain initialization vector.
  3. Syntax: decryptWithManagedIV (algorithmName, privateKey, IVAndCipherText)
  4. 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 newRecords){ 

        List mailmsg = new List(); 

        List financeList = new List(); 

        Set recIds = new Set(); 

        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: 

 

     

         

         

             

                 

             

             

                 

             

         

       

 

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.Standard Controller 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.
  2. The length of the private key must match to the specified algorithm: 128 bits, 192 bits or 256 bits.
  3. The private key should not be hardcoded in the apex code. Instead, it should be placed in a protected custom setting.
  4. The methods encrypt(), decrypt(), encryptWithManagedIV(), decryptWithManagedIV()only support blob as parameters except the algorithm name.

Reference: 

Apex crypto class

About MST

At MST Solutions our cornerstone is to adapt, engage and create solutions which guarantee the success of our clients. The talent of our team and experiences in varied business verticals gives us an advantage over other competitors.

Recent Articles

Require Permission to View Lookup Fields (Critical Update)

We have a scenario to assign the record owner to a Queue based on some criteria. The non-admin users are unable to view the value of the Owner field once the Owner field is updated with the Queue. We found the root cause for this issue. One of the features of the Spring 20 release (Require Permission to View Record Names in Lookup Fields (Critical Update) causes this issue.

Read Article »

Work with us.

Our people aren’t just employees, they are key to the success of our business. We recognize the strengths of each individual and allow them time and resources to further develop those skills, crafting a culture of leaders who are passionate about where they are going within our organization.