0

We have an Apex method in our Org which is exposed for a GET API request. The data is encrypted with AES256 before sending. However from the receiver end (Same Org for testing purpose), decryption of the data is failing with error System.SecurityException: Input length must be multiple of 16 when decrypting with padded cipher

I have checked the IV, key and the AlgorirthmName at both Sender and Receiver end. It's not an issue with the format or a conflict in their values ( Tried them without the API calls and it was successful). I am assuming that the Data Integration is getting corrupted in the API transit OR is the encrypted data itself needs to be in multiples of 16 bytes? If so, how to do that? Did anyone else have the same issue? Or anyway to debug it?

Below sample code

Sender Apex Class

@RestResource(urlMapping='/sampleMethod/Opportunities/*')
global with sharing class OpportunityInfo{

@HttpGet global static void getOpportunities() {

RestResponse res = RestContext.response;

List<Opportunity> optydata = [Select Id, Name from Opportunity LIMIT 100];

Blob exampleIv = Blob.valueOf('Example of IV123');
Blob key = Crypto.generateAesKey(256);
Blob data = Blob.valueOf(JSON.serialize(optydata));
Blob encrypted = Crypto.encrypt('AES256', key, exampleIv, data);

res.ResponseBody = encrypted;
res.statusCode = 200;

} }

Receiver Apex Class

public class sampleReceiverClass{

HttpRequest request2 = new HttpRequest(); request2.setEndpoint('https:// <orgURL>/services/apexrest/sampleMethod/Opportunities'); request2.setMethod('GET'); request2.setHeader('Authorization', 'Bearer ' + accessToken); // Access Token received //from a different method, not shown here

Http http2 = new Http(); HttpResponse response2 = http2.send(request2);

system.debug('response2 getbody=='+response2.getStatusCode()); // Status code is 200

Blob encrypteddata = Blob.valueOf(response2.getbody()); // Blob encrypteddata = response2.getBodyAsBlob(); // This works!! String initializationVector = <IV String>; String encrytpionKey = <Key>; String algorithmName = 'AES256'; Blob keyBlob = EncodingUtil.base64Decode(encrytpionKey); Blob IV = Blob.valueOf(initializationVector);

Blob decrypted = Crypto.decrypt(algorithmName, keyBlob, IV, encrypteddata); // Getting Error here

}

Brav
  • 710
  • 4
  • 16
  • 41
  • You need to encode the blob before transmitting and then decode on receipt. The comments in https://salesforce.stackexchange.com/questions/406351/why-am-i-getting-input-length-must-be-multiple-of-16-when-decrypting-with-padde explain the error message – identigral Oct 26 '23 at 05:55
  • If I understand correct, I need to encode the encrypted Blob to a base64 String and then back to Blob using the EncodingUtil methods 'base64Encode()' and 'base64Decode()' respectively before assigning it as response body? – Brav Oct 26 '23 at 07:36
  • Yes, give that a shot – identigral Oct 26 '23 at 08:22
  • Didn't work. Getting error 'String Exception: Not a base 64 character to decode' on the method base64Decode() at receiver end – Brav Oct 26 '23 at 12:11
  • When the response is a String, the body is a quoted String, so you can't simply base64 decode. Anyway, without base64 - REST service: you need a method that returns void, you didn't show it at all. The rest of your code will work as is. See https://trailhead.salesforce.com/content/learn/modules/apex_integration_services/apex_integration_webservices for more info. – identigral Oct 26 '23 at 20:49
  • My bad, missed that part. Updated the code with the method returning void. Although I don't understand how the response string is quoted and even if it is, do I simply remove the quotes? I mean when I check the String value it's encrypted and looks like this. GC�0_T��YQ�K3�j�� – Brav Oct 26 '23 at 21:24
  • Your code works without base64 - in your receiver, remove EncodingUtil.base64Decode, it decrypts for us. – identigral Oct 27 '23 at 15:24
  • Got it to work!! I can decrypt it if I get the response via getBodyAsBlob() method instead of getting it as a String and converting to BLOB. (Updated code, see the commented out part), although I don't understand why the latter didn't work. Tried removing EncodingUtil.base64Decode as per your suggestion. That didn't work either. – Brav Oct 28 '23 at 22:09
  • Relying on implicit conversion of body to String and then to Blob versus raw Blob requires the conversion to use an encoding where every byte corresponds to a unique char. Default encoding is probably UTF-8 which does not have a unique string/byte mapping. This is why hex and base64 are used in crypto so much. – identigral Oct 28 '23 at 23:18

0 Answers0