I have the following Apex code and I really don't like the first few lines of code for retrieving the encryption key from a Custom Metadata Type. The main reason I don't like it is my Apex assumes that the Opportunity_Token_Encryption_Setting__mdt exists, and if it doesn't exist then the code breaks. I tried putting try catch blocks around it and that doesn't work either. Anyway here's the code:

    Opportunity_Token_Encryption_Setting__mdt[] settings = [SELECT key__c FROM Opportunity_Token_Encryption_Setting__mdt];

    Blob key = EncodingUtil.base64Decode(settings[0].key__c);

    // Generate the data to be encrypted.
    Blob data = Blob.valueOf('{"Id":"0061700000HQjEOAA1","Ts":"2018-07-23"}');

    // Encrypt the data and have Salesforce.com generate the initialization vector
    Blob encryptedData = Crypto.encryptWithManagedIV('AES256', key, data);

    String encryptedString = EncodingUtil.base64Encode(encryptedData);

    encryptedString = EncodingUtil.urlEncode(encryptedString, 'UTF-8');

    system.debug('encrypted value: ' + encryptedString);

    // Decrypt the data - the first 16 bytes contain the initialization vector
    encryptedString = EncodingUtil.urlDecode(encryptedString, 'UTF-8');
    Blob dataToDecrypt = EncodingUtil.base64Decode(encryptedString);
    Blob decryptedData = Crypto.decryptWithManagedIV('AES256', key, dataToDecrypt);

    // Decode the decrypted data for subsequent use
    String decryptedDataString = decryptedData.toString();

    system.debug('decrypted value: ' + decryptedDataString);
  • Are you saying you don't know if the object Opportunity_Token_Encryption_Setting__mdt will even be in the org... or that the object will be there but it may have zero records for the query to return to the list? – Mark Pond Aug 9 '18 at 23:28
  • Generally, the best practice for storing encryption keys is don't. It's best to use the platform-native encryption idioms rather than trying to implement secure secret storage on Salesforce, and to keep any data requiring different security needs off-platform. – David Reed Aug 10 '18 at 0:49
  • @Mark - Well, we have a large organization and I'd hate for some helpful admin who might delete the mdt object. I just wanted to detect whether or not the object was there before attempting to write a query against it. – noctufaber Aug 10 '18 at 15:24
  • @DavidReed that "best practice" is simply because Salesforce fails to provide any decent means of storing secrets (something that is standard on almost all PAAS). There should be some way to safety and securely store a secret on an ORG. The other best practices of using protected settings/metadata only work for ISV – NSjonas Apr 5 '19 at 19:54

You'll want to read Secure Coding Storing Secrets. This is what the post has to say:

The Apex crypto class provides algorithms for creating digests, MACs, signatures and AES encryption. When using the crypto functions to implement AES encryption, keys must be generated randomly and stored securely in a Protected Custom Setting or Protected Custom Metadata type. Never hardcode the key in within an Apex class.

Also, your code has another violation:

Debug logs in apex code should not contain any sensitive data (usernames, passwords, names, contact information, opportunity information, PII, etc). The debug logs include standard salesforce logs using system.debug() methods or custom debug logs created by the application. Sensitive information should also be not be sent to 3rd party by emails or other means as part of reporting possible errors.

Debugging your key is considered a security vulnerability.

In the general case, if you do a query, and you don't know if there will be any results, check to see if it's empty first:

Opportunity_Token_Encryption_Setting__mdt[] settings = [SELECT key__c FROM Opportunity_Token_Encryption_Setting__mdt];
if(settings.isEmpty()) {
  // display a friendly error here, then...
// ... rest of your code here ...
  • Agreed, I'll yank out the debug for the key. – noctufaber Aug 10 '18 at 15:26
  • 2
    I believe this is misleading (and thus a potentially dangerous answer)... unless your an ISV, a protected custom setting or metadata doesn't really do anything for you. Please correct me if I'm wrong, but anyone with admin rights would be able to extract the key. – NSjonas Apr 5 '19 at 20:12
  • 3
    Agree with @NSjonas. "WARNING Protected custom metadata types behave like public custom metadata types when they are outside of a managed package. Public custom metadata types are readable for all profiles, including the guest user. Do not store secrets, personally identifying information, or any private data in these records. Use protected custom metadata types only in managed packages. Outside of a managed package, use named credentials or encrypted custom fields to store secrets like OAuth tokens, passwords, and other confidential material." – GoldenAxe Jul 28 '19 at 21:11
  • 1
    Reference to above quote (there wasn't enough chars available): help.salesforce.com/… – GoldenAxe Jul 28 '19 at 21:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.