/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;

public class CCORE {

 private static int key;
 private static int handle;

 private static int ccinit;
 private static int ccopen;
 private static int ccsetkeys;
 private static int ccsetseed;
 private static int cctransfer;
 private static int cccomplete;
 private static int ccclose;

 public static final int TDES_ECB_128 = 0;
 public static final int AES_ECB_128  = 1;
 public static final int AES_CBC_128  = 2;
 public static final int AES_CTR_128  = 3;

 public static final int MODE_ENCRYPT = 0;
 public static final int MODE_DECRYPT = 1;

 static {
  key=NativeCode.getInstance().malloc(0x10);
  Utils.memset(key,0,0x10);

  handle=Dl.open_flags("libstd_drv_ccore.so",Dl.RTLD_NOW|Dl.RTLD_NODELETE);
  
  ccinit=Dl.getsym(handle,"CCORE_Init");
  ccopen=Dl.getsym(handle,"CCORE_Open");
  ccsetkeys=Dl.getsym(handle,"CCORE_SetKeys");
  ccsetseed=Dl.getsym(handle,"CCORE_SetIVSeed");
  cctransfer=Dl.getsym(handle,"CCORE_Transfer");
  cccomplete=Dl.getsym(handle,"CCORE_TransferComplete");
  ccclose=Dl.getsym(handle,"CCORE_Close");

  int res=NativeCode.getInstance().invoke(ccinit,0,0,0,0,0,0,0,0);
 }

 public static int Open(int algorithm_id) {
  return NativeCode.getInstance().invoke(ccopen,algorithm_id,0,0,0,0,0,0,0);
 }

 public static int SetKeys(int handle,int mode,int key_ptr,int key_len) {
  return NativeCode.getInstance().invoke(ccsetkeys,handle,mode,key_ptr,key_len,0,0,0,0);
 }

 public static int SetIVSeed(int handle,int seed_ptr,int seed_len) {
  return NativeCode.getInstance().invoke(ccsetkeys,handle,seed_ptr,seed_len,0,0,0,0,0);
 }

 public static int Transfer(int handle,int src_addr,int dst_addr,int size) {
  return NativeCode.getInstance().invoke(cctransfer,handle,src_addr,dst_addr,size,0,0,0,0);
 }

 public static int Close(int handle) {
  return NativeCode.getInstance().invoke(ccclose,handle,0,0,0,0,0,0,0);
 }

 public static void test_decrypt(int kchar,int bchar,int size) {
  for(int i=0;i<0x10;i++) {
   Memory.write_byte(key+i,kchar+i);
  }

  int src=NativeCode.getInstance().malloc(size);
  Utils.memset(src,bchar,size);

  ApiMonitor.log("src");
  byte tab[]=Utils.buf2barray(src,size);
  ApiMonitor.log_buf(tab);

  AES_ECB_decrypt(key,src,size);

  ApiMonitor.log("dst");
  tab=Utils.buf2barray(src,size);
  ApiMonitor.log_buf(tab);

  NativeCode.getInstance().free(src);
 }

 public static void test_encrypt(int kchar,int bchar,int size) {
  for(int i=0;i<0x10;i++) {
   Memory.write_byte(key+i,kchar+i);
  }

  int src=NativeCode.getInstance().malloc(size);
  Utils.memset(src,bchar,size);

  ApiMonitor.log("src");
  byte tab[]=Utils.buf2barray(src,size);
  ApiMonitor.log_buf(tab);

  AES_ECB_encrypt(key,src,size);

  ApiMonitor.log("dst");
  tab=Utils.buf2barray(src,size);
  ApiMonitor.log_buf(tab);

  NativeCode.getInstance().free(src);
 }

 public static void AES_ECB_encrypt(int key,int data,int size) {
  int ccore=Open(AES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_ENCRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_ENCRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,data,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }


 public static void AES_ECB_encrypt_raw(int key,int addr,int data,int size) {
  int ccore=Open(AES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_ENCRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_ENCRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,addr,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }

 public static void AES_ECB_decrypt(int key,int data,int size) {
  int ccore=Open(AES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_DECRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_DECRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,data,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }

 public static void AES_ECB_decrypt_raw(int key,int addr,int data,int size) {
  int ccore=Open(AES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_DECRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_DECRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,addr,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }

 public static void TDES_ECB_encrypt(int key,int data,int size) {
  int ccore=Open(TDES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_ENCRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_ENCRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,data,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }

 public static void TDES_ECB_decrypt(int key,int data,int size) {
  int ccore=Open(TDES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_DECRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  if (key!=0) {
   res=SetKeys(ccore,MODE_DECRYPT,key,0x10);
   ApiMonitor.log("SetKeys = "+Utils.hex_value(res,8));
  }

  res=Transfer(ccore,data,data,size);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));
 }


 public static void SetCWPK(int[] cpm_key) {
  int ptr=NativeCode.getInstance().malloc(0x20);
  Utils.memset(ptr,0,0x20);

  for(int i=0;i<cpm_key.length;i++) {
   Memory.write_byte(ptr+i,cpm_key[i]);
  }

  handle=Dl.open_flags("libstd_drv_scdc.so",Dl.RTLD_NOW|Dl.RTLD_NODELETE);
  int sym=Dl.getsym(handle,"SCDC_SetCWPK");
 
  int res=NativeCode.getInstance().invoke(sym,ptr,0,0,0,0,0,0,0);
  ApiMonitor.log("SCDC_SetCWPK: 0x"+Utils.hex_value(res,8));
 }

 public static void SetCWPK(int num) {
  int cpm_key1[]={0xc3, 0x78 ,0x04 ,0xb6 ,0x06 ,0xa3 ,0x26 ,0x0f ,0x0f ,0x10 ,0x20 ,0xd5 ,0xf3 ,0x4f ,0x93 ,0xc0};
  int cpm_key2[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

  if (num==0) SetCWPK(cpm_key1);
   else SetCWPK(cpm_key2);
 }

 public static void test() {
  test_encrypt(0x31,0x41,0x4000);
  test_decrypt(0x31,0x61,0x4000);
 }

 public static void test2() {
  int src=NativeCode.getInstance().malloc(0x80);
  Utils.memset(src,0,0x80);


  Memory.write_byte(src+0,0xf8); 
  Memory.write_byte(src+1,0x25);
  Memory.write_byte(src+2,0x41);
  Memory.write_byte(src+3,0x20);

  Memory.write_byte(src+12,0x20);
  Memory.write_byte(src+13,0x41);
  Memory.write_byte(src+14,0x25);
  Memory.write_byte(src+15,0xf8); 

  ApiMonitor.log("src");
  byte tab[]=Utils.buf2barray(src,0x10);
  ApiMonitor.log_buf(tab);


  int ccore=Open(AES_ECB_128);
  ApiMonitor.log("Open = "+Utils.hex_value(ccore,8));

  int res=SetKeys(ccore,MODE_ENCRYPT,0,0);
  ApiMonitor.log("SetKeyMode = "+Utils.hex_value(res,8));

  res=Transfer(ccore,src,src,0x80);
  ApiMonitor.log("Transfer = "+Utils.hex_value(res,8));

  res=Close(ccore);
  ApiMonitor.log("Close = "+Utils.hex_value(res,8));

  ApiMonitor.log("dst");
  tab=Utils.buf2barray(src,0x10);
  ApiMonitor.log_buf(tab);

  NativeCode.getInstance().free(src);
 }

}
