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, '');
}
}