// Gemplus Imports
//import com.gemplus.opencard.service.gpk.access.GPKSecretCodeRef;
import com.gemplus.opencard.service.gpk.admin.AdministrativeCardService;
import com.gemplus.opencard.service.gpk.admin.GPKAdministrativeService;
import com.gemplus.opencard.service.gpk.file.FileUtilityCardService;
//import com.gemplus.opencard.service.gpk.file.GPKFileInfo;
import com.gemplus.opencard.service.gpk.file.GPKFileSystemService;
import com.gemplus.opencard.service.gpk.file.GPKFileUtilityService;
//import com.gemplus.opencard.service.gpk.GPKObjectRegistry;
//import com.gemplus.opencard.service.gpk.GPKProperties;
import com.gemplus.opencard.service.gpk.security.GPKAdministrativeCredential;
//import com.gemplus.opencard.service.gpk.security.GPKAuthenticationCredential;
//import com.gemplus.opencard.service.gpk.security.GPKAuthorityKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKCredentialStore;
import com.gemplus.opencard.service.gpk.security.GPKRSAKeyFile;
//import com.gemplus.opencard.service.gpk.security.GPKSignatureKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKSignatureUnwrapKeyFile;
//import com.gemplus.opencard.service.gpk.security.GPKUnwrapKeyFile;
import com.gemplus.opencard.service.gpk.signature.GPKKeyGenerationService;
//import com.gemplus.opencard.service.gpk.signature.GPKKeyImportService;
import com.gemplus.opencard.service.gpk.signature.GPKKeyManagementService;
import com.gemplus.opencard.service.gpk.signature.GPKSignatureService;
import com.gemplus.opencard.service.gpk.signature.GPKStandardNames;
import com.gemplus.opencard.service.gpk.signature.KeyManagementCardService;
//import com.gemplus.opencard.service.util.ArrayUtils;
//import com.gemplus.opencard.service.util.CryptoUtils;

// Java Imports
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.util.Enumeration;
import java.util.Random;
import java.util.Random;
import java.util.Vector;
//import javax.crypto.spec.SecretKeySpec;

// Opencard Imports
import opencard.core.service.CardRequest;
import opencard.core.service.CardServiceException;
import opencard.core.service.SmartCard;
import opencard.core.terminal.*;
import opencard.core.util.HexString;
import opencard.opt.iso.fs.CardFile;
import opencard.opt.iso.fs.CardFilePath;
//import opencard.opt.iso.fs.FileAccessCardService;
import opencard.opt.iso.fs.FileSystemCardService;
import opencard.opt.security.CredentialBag;
import opencard.opt.security.PublicKeyRef;
//import opencard.opt.security.RSACRTKey;
import opencard.opt.security.RSAPrivateKey;
import opencard.opt.security.RSAPublicKey;
import opencard.opt.signature.KeyGenerationCardService;
//import opencard.opt.signature.KeyImportCardService;
import opencard.opt.signature.SignatureCardService;

// Class Test
public class Test{
  
  private SmartCard                    sc = null;  
  
  private GPKKeyGenerationService  kgs;  
  private GPKSignatureService      scs;
  private GPKKeyManagementService  kms;  
  private GPKFileSystemService     fss;
  private GPKFileUtilityService    fus;
  
  private static final CardFilePath    root = new CardFilePath(":3F00");
  private static final CardFilePath    ef_3F01 = new CardFilePath(":3F00:3F01");
  private static final CardFilePath    df_0200 = new CardFilePath(":3F00:0200");
  private static final CardFilePath    ef_0201 = new CardFilePath(":3F00:0200:0201");  
  
  // Constructor
  public Test(SmartCard sc)
      throws CardServiceException, ClassNotFoundException, CardServiceException,
	     CardTerminalException, ClassNotFoundException, InvalidKeyException {
    
    this.sc = sc;   
    
    boolean extAuth = false;
    
    // Instanciate file CardServices    
    fss = (GPKFileSystemService)
	sc.getCardService(FileSystemCardService.class, true);
    fus = (GPKFileUtilityService)
	sc.getCardService(FileUtilityCardService.class, true);

    // Instantiate GPK CardServices	
	kgs = (GPKKeyGenerationService)
	    sc.getCardService(KeyGenerationCardService.class, true);
	scs = (GPKSignatureService)
	    sc.getCardService(SignatureCardService.class, true);
	kms = (GPKKeyManagementService)
	    sc.getCardService(KeyManagementCardService.class, true);

    // Erase Card
    System.out.println("Erasing Card...");
    fus.eraseCard();        

    // Provide credentials for Administrative key :3F00:3F01
    CredentialBag               bag = new CredentialBag();
    GPKCredentialStore          store = new GPKCredentialStore();
    GPKAdministrativeCredential credential = new GPKAdministrativeCredential();

    store.storeCredential(0, credential);
    bag.addCredentialStore(store);
    fss.provideCredentials(ef_3F01, bag);            
        
    // create DF
    System.out.println("\nCreate DF " + df_0200);
    fus.createDF(df_0200, extAuth, null);

    // Generated key file : signature and unwrap key
    GPKSignatureUnwrapKeyFile generatedKeyFile = new GPKSignatureUnwrapKeyFile(
                                                ef_0201, 1024, GPKRSAKeyFile.CERTIFIED_KEY);
    kms.createGeneratedPublicKeyFile(generatedKeyFile, null);
    
    // Generate Key Pair
    System.out.println("\nGenerating Key Pair in " + ef_0201 + "...");
    kgs.generateKeyPair(null, generatedKeyFile, -1, null);

    // Sign Data
    System.out.println("\nSigning data with EF PK " + ef_0201);

    byte[] data1ToSign = "I'M SIGNING IN THE RAIN ".getBytes();
    byte[] signature1
	= scs.signData(generatedKeyFile,
		       GPKStandardNames.SHA1_RSA,
		       GPKStandardNames.PKCS_PADDING,
		       data1ToSign);

    // Verify Signed Data
    System.out.println("\nVerify Signed data with EF PK " + ef_0201);
    System.out.println("\nVerification Result : " + scs.verifySignedData(
                                        generatedKeyFile, GPKStandardNames.SHA1_RSA, 
                                        GPKStandardNames.PKCS_PADDING, data1ToSign, 
                                        signature1));
  }

  // Main()
  public static void main(String[] args) {
    try {
      SmartCard.start();

      // wait for a smartcard with file access support
      System.out.println("\nWaiting for card...\n");

      CardRequest cr = new CardRequest();
      // Deprecated fot FOR OCF 1.2. Uncomment above instead
      // CardRequest cr = new CardRequest(CardRequest.ANYCARD, null, null);
      SmartCard   card = SmartCard.waitForCard(cr);
      
      System.out.println("Card detected\n");

      // Instantiate the Test class
      Test test1 = new Test(card);
      
    } catch(Exception e) {
      e.printStackTrace();
    } 
    finally {
      try {
        SmartCard.shutdown();
        System.exit(0);
      } catch(Exception e) {
        e.printStackTrace();
      } 
    } 
  }     
}
