[SalesForce] Integer Array to Base64 String

So I am struggling a bit to convert some code written in java to APEX.
The struggle here is that I have an integer array as one of my encryption key, it looks something similar to this below:

[242, 2, 56, 23, 15, 5, 12, 105, 19, 47, 116, 89, 25, 152, 200, 215]

and in java I convert it to 128 bytes

[-14, 2, 56, 23, 15, 5, 12, 105, 19, 47, 116, 89, 25, -104, -56, -41]

and then to Base64 I get 8gI4Fw8FDGkTL3RZGZjI1w== that is then used as the IvParameterSpec() in the jave Crypto package.

However, I can't figure out to save my life how to do that in apex? The integer array will be an initialization vector for "AES128" encryption.

I tried this:

List<Integer> values256 = new List<Integer>{242, 2, 56, 23, 15, 5, 12, 105, 19, 47, 116, 89, 25, 152, 200, 215};
List<Integer> values128 = new List<Integer>();
    for(Integer bytes : values256){

        if(bytes > 127){
            values128.add((256-bytes)*-1);
        }else{
            values128.add(bytes);
        }   
    }



String encodedString = String.fromCharArray(values128);
String myBase64String = EncodingUtil.base64Encode(Blob.valueof(encodedString));
System.Debug(values128);
System.Debug(myBase64String);

But my base64 string looks like this: 77+yAjgXDwUMaRMvdFkZ776Y77+I77+X which is very different from what I get in Java. Any idea on what I am doing wrong?

EDIT: I wanted to add that I am really new to the world of encryption so I may be missing some obvious fundamentals! So feel free to correct me…

Best Answer

String.fromCharArray is going to create a UTF-8 encoded string, which will alter the bytes in the stream. For example, 242 will be encoded as two bytes instead of one. Any value outside 0-127 will be encoded as multiple bytes when using this function, including all negative integers. Since we can't really work with binary data directly in Apex Code, just store the base-64 encoded value directly in a string or some persistent storage (e.g. a custom setting).


public class Base64 {
    static String[] codes = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('');

    // Encodes integers 0-255 into base 64 string
    public static String encode(Integer[] source) {
        // Preallocate memory for speed
        String[] result = new String[(source.size()+2)/3];
        // Every three bytes input becomes four bytes output
        for(Integer index = 0, size = source.size()/3; index < size; index++) {
            // Combine three bytes in to one single integer
            Integer temp = (source[index]<<16|source[index+1]<<8)|source[index+2];
            // Extract four values from 0-63, and use the code from the base 64 index
            result[index]=codes[temp>>18]+(codes[(temp>>12)&63])+(codes[(temp>>6)&63])+codes[temp&63];
        }
        if(Math.mod(source.size(),3)==1) {
            // One byte left over, need two bytes padding
            Integer temp = (source[source.size()-1]<<16);
            result[result.size()-1] = codes[temp>>18]+(codes[(temp>>12)&63])+codes[64]+codes[64];
        } else if(Math.mod(source.size(),3)==2) {
            // Two bytes left over, need one byte padding
            Integer temp = (source[source.size()-2]<<16)|(source[source.size()-1]<<8);
            result[result.size()-1] = codes[temp>>18]+(codes[(temp>>12)&63])+(codes[(temp>>6)&63])+codes[64];
        }
        // Join into a single string
        return String.join(result, '');
    }
}
Related Topic