package com.atolsystems.memop.scramblers;
import com.atolsystems.atolutilities.MemRange;
import com.atolsystems.atolutilities.AArrayUtilities;
import com.atolsystems.atolutilities.ProgrammingChunk;
import com.atolsystems.memop.AbstractMemScrambler;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author sebastien.riou
*/
public class AesMemCodec2 extends AbstractMemScrambler {
@Override
public void addressScrambling(boolean encrypt, List<ProgrammingChunk> image) {
//no address scrambling
}
@Override
public ProgrammingChunk processChunk(boolean encrypt, ProgrammingChunk chunk, byte[] key) {
ProgrammingChunk out;
byte[] dataIn = chunk.getData();
byte[] dataOut = new byte[dataIn.length];
if (0 != (dataIn.length % 16)) {
throw new RuntimeException("Unsupported data length: dataIn.length%16");
}
switch (key.length) {
case 8:
case 16:
//case 24:
//case 32:
break;
default:
throw new RuntimeException("Unsupported key length: key must be 8, 16 bytes long");
}
try {
for (int i = 0; i < dataIn.length; i += 16) {
long address = chunk.getAddress() + i;
byte[] iv = new byte[16];
iv[0] = (byte) (0xFF & (address >> 16));
iv[1] = (byte) (0xFF & (address >> 8));
iv[2] = (byte) (0xFF & address);
iv[3] = (byte) (0xFF & (address >> 16));
iv[4] = (byte) (0xFF & (address >> 8));
iv[5] = (byte) (0xFF & address);
iv[6] = (byte) (0xFF & (address >> 8));
iv[7] = (byte) (0xFF & address);
byte[] key16=new byte[16];
System.arraycopy(key, 0, key16, 0, key.length);
byte[] keyMsb=AArrayUtilities.xor(key16, 8, iv, 0, 8);
System.arraycopy(keyMsb, 0, key16, 8, 8);
//compute the session key
SecretKeySpec skeySpec = new SecretKeySpec(key16, "AES");
//IvParameterSpec ivSpec = new IvParameterSpec(iv);
// Instantiate the cipher
Cipher cipher;
cipher = Cipher.getInstance("AES/ECB/NoPadding");
if (encrypt) {
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
}
byte[] temp = cipher.doFinal(dataIn);
System.arraycopy(temp, 0, dataOut, i, 16);
}
} /*catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(AesMemCodec2.class.getName()).log(Level.SEVERE, null, ex);
}*/ catch (IllegalBlockSizeException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
out = new ProgrammingChunk(chunk.getAddress(), dataOut);
return out;
}
}