Sto lavorando su un sistema di trasferimento elettronico dei fondi (EFT) e devo stare molto attento con i dati sensibili come i numeri delle carte di credito.
Abbiamo bisogno di queste informazioni montare i dati ISO 8583 prima di inviarli ai gateway EFT.
Utilizziamo char [] e byte [] per mantenere i dati sensibili e utilizzare Array.fill quando non abbiamo più bisogno di queste informazioni.
Pensando a migliorare la sicurezza, pensa di creare una classe per includere queste informazioni sensibili e magari mantenere i dati crittografati fino al momento necessario.
Ecco il codice che intendo utilizzare con una chiave generata a caso.
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.security.auth.Destroyable;
public final class SensitiveChars implements CharSequence, Destroyable {
private static final int KEYSIZE = 56;
private static final String DES = "DES";
private static final String DES_ECB_PKCS5_PADDING = DES + "/ECB/PKCS5Padding";
private byte[] data;
private Charset charset;
private int lenght;
private SecretKey secretKey;
public SensitiveChars(char[] data) {
super();
this.charset = Charset.defaultCharset();
ByteBuffer byteBuffer = charset.encode(CharBuffer.wrap(data));
lenght = data.length;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(DES);
SecureRandom secureRandom = new SecureRandom();
int keyBitSize = KEYSIZE;
keyGenerator.init(keyBitSize, secureRandom);
secretKey = keyGenerator.generateKey();
setRawData(byteBuffer.array());
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
public static SensitiveChars of(byte[] bytes) {
return of(bytes, Charset.defaultCharset());
}
public static SensitiveChars of(byte[] bytes, Charset charset) {
return of(bytes, charset, false);
}
public static SensitiveChars of(byte[] bytes, Charset charset, boolean cleanBytes) {
char[] chars = toChar(bytes, charset, cleanBytes);
return new SensitiveChars(chars);
}
@Override
public int length() {
return lenght;
}
@Override
public char charAt(int index) {
char[] tempArray = getChars();
char c = tempArray[index];
clearData(tempArray);
return c;
}
@Override
public CharSequence subSequence(int start, int end) {
char[] dataTmp = getChars();
char[] range = Arrays.copyOfRange(dataTmp, start, end);
clearData(dataTmp);
return new SensitiveChars(range);
}
public char[] getChars() {
if (lenght == 0) {
return new char[0];
} else {
byte[] rawData = getRawData();
ByteBuffer byteBuffer = ByteBuffer.wrap(rawData);
CharBuffer charBuffer = charset.decode(byteBuffer);
char[] result = Arrays.copyOf(charBuffer.array(), lenght);
clearData(charBuffer.array());
clearData(rawData);
return result;
}
}
public void append(char[] chars) {
char[] dataTmp = getChars();
int lengthData = dataTmp.length;
char[] newData = Arrays.copyOf(dataTmp, lengthData + chars.length);
clearData(data);
int posIni = lengthData;
for (int i = 0; i < chars.length; i++) {
newData[i + posIni] = chars[i];
}
CharBuffer charBuffer = CharBuffer.wrap(newData);
ByteBuffer byteBuffer = charset.encode(charBuffer);
byteBuffer.compact();
setRawData(byteBuffer.array());
lenght = newData.length;
clearData(dataTmp);
clearData(newData);
}
private void setRawData(byte[] data) {
this.data = encrypt(data);
}
private byte[] getRawData() {
return decrypt(data);
}
@Override
public void destroy() {
clearData(data);
data = new byte[0];
lenght = 0;
}
private byte[] encrypt(byte[] bytes) {
try {
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(bytes);
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
| BadPaddingException e) {
throw new IllegalStateException(e);
}
}
private byte[] decrypt(byte[] bytes) {
try {
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5_PADDING);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(bytes);
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
| BadPaddingException e) {
throw new IllegalStateException(e);
}
}
private static void clearData(byte[] cs) {
Arrays.fill(cs, (byte) 0);
}
private static void clearData(char[] cs) {
CharsUtils.clearData(cs);
}
}
È una buona idea o devo usare un altro approccio?
Modifica 1: La nostra applicazione deve essere conforme al link