// copyright 2001
// the regents of the university of michigan
// all rights reserved
// 
// permission is granted to use, copy, create derivative works 
// and redistribute this software and such derivative works 
// for any purpose, so long as the name of the university of 
// michigan is not used in any advertising or publicity 
// pertaining to the use or distribution of this software 
// without specific, written prior authorization.  if the 
// above copyright notice or any other identification of the 
// university of michigan is included in any copy of any 
// portion of this software, then the disclaimer below must 
// also be included.
// 
// this software is provided as is, without representation 
// from the university of michigan as to its fitness for any 
// purpose, and without warranty by the university of 
// michigan of any kind, either express or implied, including 
// without limitation the implied warranties of 
// merchantability and fitness for a particular purpose. the 
// regents of the university of michigan shall not be liable 
// for any damages, including special, indirect, incidental, or 
// consequential damages, with respect to any claim arising 
// out of or in connection with the use of the software, even 
// if it has been or is hereafter advised of the possibility of 
// such damages.

// Written by Jim Rees July 2000

import javacard.framework.*;
import javacardx.framework.*;
import javacardx.crypto.*;

public class secbdes extends javacard.framework.Applet {
    final byte secb_CLA = (byte) 0x04;
    final byte Encrypt = (byte) 0x0e;
    final byte Decrypt = (byte) 0x10;
    final byte GetResponse = (byte) 0xc0;

    byte IV[];

    DES_Key deskey;

    private secbdes() {
	deskey = new DES_Key((short)1);
	IV = new byte[64];
	deskey.setICV(IV, (short)0);
	deskey.clearICV();
	register();
    }

    public static void install(APDU apdu) {
	new secbdes();
    }

    public boolean select() {
	return true;
    }

    public static void main(String args[]) {
	ISOException.throwIt((short) 0x7264);
    }

    public void process(APDU apdu) {
	short len, status = ISO.SW_NO_ERROR;
	byte b[] = apdu.getBuffer();

	// Check cla & ins
	if (b[ISO.OFFSET_CLA] != secb_CLA) {
	    if (b[ISO.OFFSET_INS] == ISO.INS_SELECT) {
		if (b[ISO.OFFSET_P1] != 4)
		    status = ISO.SW_WRONG_P1P2;
	    } else if (b[ISO.OFFSET_INS] != GetResponse)
		status = ISO.SW_CLA_NOT_SUPPORTED;
	}
	if (status != ISO.SW_NO_ERROR)
	    ISOException.throwIt(status);

	switch (b[ISO.OFFSET_INS]) {
	case ISO.INS_SELECT:
	case GetResponse:
	    break;
	case Encrypt:
	    len = apdu.setIncomingAndReceive();
	    while (len % (short)8 != 0)
		b[(short)ISO.OFFSET_CDATA + len++] = (short)0;
	    deskey.encryptCBC(b, (short)ISO.OFFSET_CDATA, len, b, (short)ISO.OFFSET_CDATA);
	    apdu.setOutgoingAndSend((short)ISO.OFFSET_CDATA, len);
	    break;
	case Decrypt:
	    len = apdu.setIncomingAndReceive();
	    deskey.decryptCBC(b, (short)ISO.OFFSET_CDATA, len, b, (short)ISO.OFFSET_CDATA);
	    apdu.setOutgoingAndSend((short)ISO.OFFSET_CDATA, len);
	    break;
	default:
	    status = ISO.SW_INS_NOT_SUPPORTED;
	}

	if (status != ISO.SW_NO_ERROR)
	    ISOException.throwIt(status);
    }
}
