>From f90af770ac1e51cb3c3bcafda4c24a4ad3894d68 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Tue, 7 Feb 2012 22:40:06 -0500
Subject: [PATCH 15/16] Moved client functions to CryptoUtil.java and added
 GenPKIArchiveOptions tool

---
 .../src/com/netscape/cms/servlet/test/DRMTest.java |  255 ++++---------------
 .../servlet/test/GeneratePKIArchiveOptions.java    |  222 +++++++++++++++++
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    |  143 +++++++++++
 3 files changed, 419 insertions(+), 201 deletions(-)
 create mode 100644 pki/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java

diff --git a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index 341561a0f7f5db7d981887df0fc33c8512a80ed5..7196f93c0e061465aa798853838135671d9a449a 100644
--- a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -17,46 +17,18 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.test;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.CharConversionException;
-import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateEncodingException;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Random;
 
 import org.mozilla.jss.CryptoManager;
-import org.mozilla.jss.asn1.BIT_STRING;
-import org.mozilla.jss.asn1.InvalidBERException;
-import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
-import org.mozilla.jss.asn1.OCTET_STRING;
 import org.mozilla.jss.crypto.AlreadyInitializedException;
-import org.mozilla.jss.crypto.BadPaddingException;
-import org.mozilla.jss.crypto.Cipher;
 import org.mozilla.jss.crypto.CryptoToken;
 import org.mozilla.jss.crypto.EncryptionAlgorithm;
 import org.mozilla.jss.crypto.IVParameterSpec;
-import org.mozilla.jss.crypto.IllegalBlockSizeException;
 import org.mozilla.jss.crypto.KeyGenAlgorithm;
-import org.mozilla.jss.crypto.KeyGenerator;
-import org.mozilla.jss.crypto.KeyWrapAlgorithm;
-import org.mozilla.jss.crypto.KeyWrapper;
-import org.mozilla.jss.crypto.PBEAlgorithm;
 import org.mozilla.jss.crypto.SymmetricKey;
-import org.mozilla.jss.crypto.TokenException;
-import org.mozilla.jss.crypto.X509Certificate;
-import org.mozilla.jss.pkcs11.PK11SecureRandom;
-import org.mozilla.jss.pkcs12.PasswordConverter;
-import org.mozilla.jss.pkcs7.EncryptedContentInfo;
-import org.mozilla.jss.pkix.crmf.EncryptedKey;
-import org.mozilla.jss.pkix.crmf.EncryptedValue;
-import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
-import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
 import org.mozilla.jss.util.Password;
 
 import org.apache.commons.cli.CommandLine;
@@ -71,8 +43,8 @@ import com.netscape.cms.servlet.key.model.KeyData;
 import com.netscape.cms.servlet.key.model.KeyDataInfo;
 import com.netscape.cms.servlet.request.KeyRequestResource;
 import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 
-@SuppressWarnings("deprecation")
 public class DRMTest {
 
     public static void usage(Options options) {
@@ -129,20 +101,19 @@ public class DRMTest {
         }
 
         // used for crypto operations
-        byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
-        IVParameterSpec IV = null;
-        IVParameterSpec IV_server = null;
-        
+        byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; 
+        IVParameterSpec ivps = null;
+        IVParameterSpec ivps_server = null;
+
         try {
-            IV = genIV(8);
+            ivps = genIV(8);
         } catch (Exception e) {
             log("Can't generate initialization vector use default: " + e.toString());
-            IV = new IVParameterSpec(iv);
+            ivps = new IVParameterSpec(iv);
         }
         
         CryptoManager manager = null;
         CryptoToken token = null;
-        KeyGenerator kg1 = null;
 
         // used for wrapping to send data to DRM
         String transportCert = null;
@@ -239,10 +210,9 @@ public class DRMTest {
         log("Archiving symmetric key");
         clientId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
         try {
-            kg1 = token.getKeyGenerator(KeyGenAlgorithm.DES3);
-            vek = kg1.generate();
-            
-            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1, IV);
+            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
+                    KeyGenAlgorithm.DES3, ivps);
 
             KeyRequestInfo info = client.archiveSecurityData(encoded, clientId, KeyRequestResource.SYMMETRIC_KEY_TYPE);
             log("Archival Results:");
@@ -273,9 +243,9 @@ public class DRMTest {
         // Test 6: Submit a recovery request for the symmetric key using a session key
         log("Submitting a recovery request for the  symmetric key using session key");
         try {
-            recoveryKey = kg1.generate();
-            wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, IV.getIV());
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+            KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
             recoveryRequestId = getId(info.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
@@ -288,12 +258,14 @@ public class DRMTest {
         // Test 8: Get key
         log("Getting key: " + keyId);
 
-        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, IV.getIV());
+        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        
-        IV_server = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
+
+        ivps_server = new IVParameterSpec(com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
         try {
-            recoveredKey = unwrap(token, IV_server,com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
+            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, 
+                    com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey),
+                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -310,11 +282,12 @@ public class DRMTest {
         recoveryPassphrase = "Gimme me keys please";
 
         try {
-            recoveryKey = kg1.generate();
-            wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, IV, recoveryKey);
-            wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            
-            requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+                    EncryptionAlgorithm.DES3_CBC_PAD);
+            wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+
+            requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
             recoveryRequestId = getId(requestInfo.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using passphrase" + e.toString());
@@ -327,12 +300,16 @@ public class DRMTest {
 
         // Test 11: Get key
         log("Getting key: " + keyId);
-        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        
-        recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
 
-        
+        try {
+            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+        } catch (Exception e) {
+            log("Error: unable to unwrap key using passphrase");
+            e.printStackTrace();
+        }
+
         if (recoveredKey == null || !recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
             log("Error: recovered and archived keys do not match!");
         } else {
@@ -344,7 +321,8 @@ public class DRMTest {
         // Test 12: Generate and archive a passphrase
         clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
         try {
-            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1, IV);
+            byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
+                    KeyGenAlgorithm.DES3, ivps);
             requestInfo = client.archiveSecurityData(encoded, clientId, KeyRequestResource.PASS_PHRASE_TYPE);
             log("Archival Results:");
             printRequestInfo(requestInfo);
@@ -376,10 +354,11 @@ public class DRMTest {
         recoveryRequestId = null;
         wrappedRecoveryKey = null;
         try {
-            recoveryKey = kg1.generate();
-            wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, IV, recoveryKey);
-            requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, IV.getIV());
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+            wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+                    EncryptionAlgorithm.DES3_CBC_PAD);
+            requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
             recoveryRequestId = getId(requestInfo.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering passphrase using session key: " + e.getMessage());
@@ -392,11 +371,13 @@ public class DRMTest {
         // Test 16: Get key
         log("Getting passphrase: " + keyId);
 
-        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, IV.getIV());
+        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        IV_server = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
+        ivps_server = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
         try {
-            recoveredKey = unwrap(token, IV_server, com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
+            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server, 
+                    com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey),
+                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
             recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
@@ -411,7 +392,7 @@ public class DRMTest {
 
         // Test 17: Submit a recovery request for the passphrase using a passphrase
         log("Submitting a recovery request for the passphrase using a passphrase");
-        requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+        requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
         recoveryRequestId = getId(requestInfo.getRequestURL());
 
         //Test 18: Approve recovery
@@ -420,13 +401,14 @@ public class DRMTest {
 
         // Test 19: Get key
         log("Getting passphrase: " + keyId);
-        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
         try {
+            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
             recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
         } catch (Exception e) {
-            log("Error: Can't convert recovered passphrase from binary to ascii!");
+            log("Error: cannot unwrap key using passphrase");
+            e.printStackTrace();
         }
 
         if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
@@ -448,13 +430,14 @@ public class DRMTest {
 
         // Test 22: Get key
         log("Getting passphrase: " + keyId);
-        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
         try {
+            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
             recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
         } catch (Exception e) {
-            log("Error: Can't convert recovered passphrase from binary to ascii!");
+            log("Error: Can't unwrap recovered key using passphrase");
+            e.printStackTrace();
         }
 
         if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
@@ -464,145 +447,15 @@ public class DRMTest {
         }
     }
 
-    private static String unwrap(String wrappedRecoveredKey, String recoveryPassphrase) {
-
-        EncryptedContentInfo cInfo = null;
-        String unwrappedData = null;
-        
-        //We have to do this to get the decoding to work.
-        PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
-        
-        log("pbeAlg: " + pbeAlg);
-        try {
-            Password pass = new Password(recoveryPassphrase.toCharArray());
-            PasswordConverter passConverter = new
-                    PasswordConverter();
-
-            byte[] encoded = com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey);
-
-            ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
-            cInfo = (EncryptedContentInfo)
-                      new EncryptedContentInfo.Template().decode(inStream);
-
-            byte[] decodedData = cInfo.decrypt(pass, passConverter);
-
-            unwrappedData = com.netscape.osutil.OSUtil.BtoA(decodedData);
-
-        } catch (Exception e) {
-            log("Problem unwraping PBE wrapped datat! " + e.toString());
-
-        }
-
-        return unwrappedData;
-    }
-
     private static void log(String string) {
         // TODO Auto-generated method stub
         System.out.println(string);
     }
 
-    private static String unwrap(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
-            SymmetricKey recoveryKey) throws NoSuchAlgorithmException, TokenException, BadPaddingException,
-            IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
-
-        Cipher decryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
-        decryptor.initDecrypt(recoveryKey, IV);
-        byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
-        String unwrappedS = com.netscape.osutil.OSUtil.BtoA( unwrappedData);
-
-        return unwrappedS;
-    }
-
     private static String getId(String link) {
         return link.substring(link.lastIndexOf("/") + 1);
     }
 
-    private static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
-            SymmetricKey vek, String passphrase, KeyGenerator kg1, IVParameterSpec IV) throws TokenException, CharConversionException,
-            NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
-            CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
-            BadPaddingException {
-        byte[] key_data = null;
-
-        //generate session key
-        SymmetricKey sk = kg1.generate();
-
-        if (passphrase != null) {
-            key_data = wrapPassphrase(token, passphrase, IV, sk);
-        } else {
-            // wrap payload using session key
-            KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
-            wrapper1.initWrap(sk, IV);
-            key_data = wrapper1.wrap(vek);
-        }
-
-        // wrap session key using transport key
-        byte[] session_data = wrapSymmetricKey(manager, token, transportCert, sk);
-
-        // create PKIArchiveOptions structure
-        AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
-                new OCTET_STRING(IV.getIV()));
-        EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
-                new BIT_STRING(key_data, 0));
-        EncryptedKey key = new EncryptedKey(encValue);
-        PKIArchiveOptions opt = new PKIArchiveOptions(key);
-        
-        byte[] encoded = null;
-        
-        try {
-          
-            //Let's make sure we can decode the encoded PKIArchiveOptions..
-          ByteArrayOutputStream oStream = new ByteArrayOutputStream();
-          
-          opt.encode(oStream);
-          
-          encoded = oStream.toByteArray();
-          ByteArrayInputStream inStream = new ByteArrayInputStream( encoded);
-          PKIArchiveOptions  options = (PKIArchiveOptions)
-                    (new PKIArchiveOptions.Template()).decode(inStream);
-          log("Decoded PKIArchiveOptions: " + options);
-        } catch (IOException e) {
-            log("Problem with PKIArchiveOptions: " + e.toString());
-            return null;
-            
-        } catch (InvalidBERException e) {
-            log("Problem with PKIArchiveOptions: " + e.toString());
-            return null;
-        }
-        
-        return encoded;
-    }
-
-    private static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk)
-            throws NoSuchAlgorithmException, TokenException, InvalidKeyException,
-            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
-        byte[] wrappedPassphrase = null;
-        Cipher encryptor = null;
-
-        encryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
-        log("cipher " + encryptor);
-
-        if (encryptor != null) {
-            encryptor.initEncrypt(sk, IV);
-            wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
-        } else {
-            throw new IOException("Failed to create cipher");
-        }
-        
-        return wrappedPassphrase;
-    }
-
-    private static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert,
-            SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException,
-            InvalidKeyException, InvalidAlgorithmParameterException {
-        byte transport[] = com.netscape.osutil.OSUtil.AtoB(transportCert);
-        X509Certificate tcert = manager.importCACertPackage(transport);
-        KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
-        rsaWrap.initWrap(tcert.getPublicKey(), null);
-        byte session_data[] = rsaWrap.wrap(sk);
-        return session_data;
-    }
-
     private static void printRequestInfo(KeyRequestInfo info) {
         log("KeyRequestURL: " + info.getRequestURL());
         log("Key URL:       " + info.getKeyURL());
diff --git a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cfc685f39dc3ab8871b5a4be64e83eecd3a216b
--- /dev/null
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
@@ -0,0 +1,222 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.CharConversionException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.crypto.CryptoUtil;
+import com.netscape.osutil.OSUtil;
+
+@SuppressWarnings("deprecation")
+public class GeneratePKIArchiveOptions {
+    
+    public static void usage(Options options) {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("GeneratePKIArchiveOptions", options);
+        System.exit(1);
+    }
+    
+    private static void log(String string) {
+        // TODO Auto-generated method stub
+        System.out.println(string);
+    }
+    
+    // read in byte array
+    // we must do this somewhere?
+    public static byte[] read(String fname) throws IOException {
+        File file = new File(fname);
+        byte[] result = new byte[(int) file.length()];
+        try {
+            InputStream input = null;
+            try {
+                int totalBytesRead = 0;
+                input = new BufferedInputStream(new FileInputStream(file));
+                while (totalBytesRead < result.length) {
+                    int bytesRemaining = result.length - totalBytesRead;
+                    //input.read() returns -1, 0, or more :
+                    int bytesRead = input.read(result, totalBytesRead, bytesRemaining);
+                    if (bytesRead > 0) {
+                        totalBytesRead = totalBytesRead + bytesRead;
+                    }
+                }
+            } finally {
+                input.close();
+            }
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+
+        return result;
+    }
+    
+    public static void write(byte[] aInput, String outFile) throws IOException {
+        try {
+            OutputStream output = null;
+            try {
+                output = new BufferedOutputStream(new FileOutputStream(outFile));
+                output.write(aInput);
+            } finally {
+                output.close();
+            }
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+    
+    private static void write_file(String data, String outFile) throws IOException {
+        FileWriter fstream = new FileWriter(outFile);
+        BufferedWriter out = new BufferedWriter(fstream);
+        out.write(data);
+        //Close the output stream
+        out.close();
+    }
+
+    public static void main(String args[]) throws InvalidKeyException, CertificateEncodingException,
+            CharConversionException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+            IllegalStateException, TokenException, IOException, IllegalBlockSizeException, BadPaddingException,
+            InvalidBERException, NotExtractableException {
+        String token_pwd = null;
+        String db_dir = "./";
+        String out_file = "./options.out";
+        String transport_file = "./transport.crt";
+        String key_file = "./symkey.out";
+        String passphrase = null;
+        boolean passphraseMode = false;
+
+        // parse command line arguments
+        Options options = new Options();
+        options.addOption("w", true, "Token password (required)");
+        options.addOption("d", true, "Directory for tokendb");
+        options.addOption("p", true, "Passphrase");
+        options.addOption("t", true, "File with transport cert");
+        options.addOption("o", true, "Output file");
+        options.addOption("k", true, "Key file");
+        
+        try {
+            CommandLineParser parser = new PosixParser();
+            CommandLine cmd = parser.parse(options, args);
+            
+            if (cmd.hasOption("p")) {
+                passphrase = cmd.getOptionValue("p");
+                passphraseMode = true;
+            }
+            
+            if (cmd.hasOption("o")) {
+                out_file = cmd.getOptionValue("o");
+            }
+            
+            if (cmd.hasOption("k")) {
+                key_file = cmd.getOptionValue("k");
+            }
+            
+            if (cmd.hasOption("t")) {
+                transport_file = cmd.getOptionValue("t");
+            }
+            
+            if (cmd.hasOption("w")) {
+                token_pwd = cmd.getOptionValue("w");
+            } else {
+                System.err.println("Error: no token password provided");
+                usage(options);
+            }
+
+            if (cmd.hasOption("d")) {
+                db_dir = cmd.getOptionValue("d");
+            }
+
+        } catch (ParseException e) {
+            System.err.println("Error in parsing command line options: " + e.getMessage());
+            usage(options);
+        }
+
+        // used for crypto operations
+        byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+        IVParameterSpec ivps = new IVParameterSpec(iv);
+        CryptoManager manager = null;
+        CryptoToken token = null;
+
+        // used for wrapping to send data to DRM
+        byte[] tcert = read(transport_file);
+        String transportCert = com.netscape.osutil.OSUtil.BtoA(tcert);
+
+        // Initialize token
+        try {
+            CryptoManager.initialize(db_dir);
+        } catch (AlreadyInitializedException e) {
+            // it is ok if it is already initialized 
+        } catch (Exception e) {
+            log("INITIALIZATION ERROR: " + e.toString());
+            System.exit(1);
+        }
+
+        // log into token
+        try {
+            manager = CryptoManager.getInstance();
+            token = manager.getInternalKeyStorageToken();
+            Password password = new Password(token_pwd.toCharArray());
+            try {
+                token.login(password);
+            } catch (Exception e) {
+                log("login Exception: " + e.toString());
+                if (!token.isLoggedIn()) {
+                    token.initPassword(password, password);
+                }
+            }
+        } catch (Exception e) {
+            log("Exception in logging into token:" + e.toString());
+        }
+        
+        // Data to be archived
+        SymmetricKey vek = null;
+        if (!passphraseMode) {
+            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            // store vek in file
+            write_file(OSUtil.BtoA(vek.getKeyData()), key_file);
+        }
+
+        byte[] encoded = null;
+        
+        if (passphraseMode) {
+            encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase, 
+                    KeyGenAlgorithm.DES3, ivps);
+        } else {
+            encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null, 
+                    KeyGenAlgorithm.DES3, ivps);
+        }
+        
+        // write encoded to file
+        write_file(OSUtil.BtoA(encoded), out_file);
+
+    }
+}
diff --git a/pki/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/pki/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index cad7d0ae3452617dea6ce7b84c62d838e5154a01..38b405673598f64df82c2a1343ae1a33eb3eb8a8 100644
--- a/pki/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/pki/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -24,6 +24,7 @@ import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
@@ -64,35 +65,53 @@ import netscape.security.x509.X509CertInfo;
 import netscape.security.x509.X509Key;
 
 import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
 import org.mozilla.jss.NoSuchTokenException;
 import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
 import org.mozilla.jss.asn1.InvalidBERException;
 import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
 import org.mozilla.jss.asn1.SEQUENCE;
 import org.mozilla.jss.crypto.Algorithm;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
 import org.mozilla.jss.crypto.CryptoStore;
 import org.mozilla.jss.crypto.CryptoToken;
 import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
 import org.mozilla.jss.crypto.InternalCertificate;
 import org.mozilla.jss.crypto.InvalidKeyFormatException;
 import org.mozilla.jss.crypto.KeyGenAlgorithm;
 import org.mozilla.jss.crypto.KeyGenerator;
 import org.mozilla.jss.crypto.KeyPairAlgorithm;
 import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
 import org.mozilla.jss.crypto.NoSuchItemOnTokenException;
 import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PBEAlgorithm;
 import org.mozilla.jss.crypto.PrivateKey;
 import org.mozilla.jss.crypto.Signature;
 import org.mozilla.jss.crypto.SignatureAlgorithm;
 import org.mozilla.jss.crypto.SymmetricKey;
 import org.mozilla.jss.crypto.TokenException;
 import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
 import org.mozilla.jss.pkix.crmf.CertReqMsg;
 import org.mozilla.jss.pkix.crmf.CertRequest;
 import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
 import org.mozilla.jss.pkix.primitive.Name;
 import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
 import org.mozilla.jss.util.Base64OutputStream;
+import org.mozilla.jss.util.Password;
 
 import com.netscape.cmsutil.util.Cert;
 import com.netscape.osutil.OSUtil;
@@ -1128,6 +1147,130 @@ public class CryptoUtil {
 
         return certs;
     }
+    
+    @SuppressWarnings("deprecation")
+    public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+            throws IOException, InvalidBERException, InvalidKeyException, IllegalStateException,
+            NoSuchAlgorithmException, InvalidAlgorithmParameterException, NotInitializedException, TokenException,
+            IllegalBlockSizeException, BadPaddingException {
+        EncryptedContentInfo cInfo = null;
+        String unwrappedData = null;
+
+        //We have to do this to get the decoding to work.
+        @SuppressWarnings("unused")
+        PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+        Password pass = new Password(recoveryPassphrase.toCharArray());
+        PasswordConverter passConverter = new
+                    PasswordConverter();
+
+        byte[] encoded = com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey);
+
+        ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+        cInfo = (EncryptedContentInfo)
+                      new EncryptedContentInfo.Template().decode(inStream);
+
+        byte[] decodedData = cInfo.decrypt(pass, passConverter);
+
+        unwrappedData = com.netscape.osutil.OSUtil.BtoA(decodedData);
+
+        return unwrappedData;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static String unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
+            SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException,
+            BadPaddingException,
+            IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+        Cipher decryptor = token.getCipherContext(alg);
+        decryptor.initDecrypt(recoveryKey, IV);
+        byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
+        String unwrappedS = com.netscape.osutil.OSUtil.BtoA(unwrappedData);
+
+        return unwrappedS;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk,
+            EncryptionAlgorithm alg)
+            throws NoSuchAlgorithmException, TokenException, InvalidKeyException,
+            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
+        byte[] wrappedPassphrase = null;
+        Cipher encryptor = null;
+
+        encryptor = token.getCipherContext(alg);
+
+        if (encryptor != null) {
+            encryptor.initEncrypt(sk, IV);
+            wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
+        } else {
+            throw new IOException("Failed to create cipher");
+        }
+
+        return wrappedPassphrase;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert,
+            SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException,
+            InvalidKeyException, InvalidAlgorithmParameterException {
+        byte transport[] = com.netscape.osutil.OSUtil.AtoB(transportCert);
+        X509Certificate tcert = manager.importCACertPackage(transport);
+        KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+        rsaWrap.initWrap(tcert.getPublicKey(), null);
+        byte session_data[] = rsaWrap.wrap(sk);
+        return session_data;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
+            SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, IVParameterSpec IV) throws TokenException,
+            CharConversionException,
+            NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
+            CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
+            BadPaddingException, InvalidBERException {
+        byte[] key_data = null;
+
+        //generate session key
+        SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg);
+
+        if (passphrase != null) {
+            key_data = wrapPassphrase(token, passphrase, IV, sk, EncryptionAlgorithm.DES3_CBC_PAD);
+        } else {
+            // wrap payload using session key
+            KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+            wrapper1.initWrap(sk, IV);
+            key_data = wrapper1.wrap(vek);
+        }
+
+        // wrap session key using transport key
+        byte[] session_data = wrapSymmetricKey(manager, token, transportCert, sk);
+
+        // create PKIArchiveOptions structure
+        AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
+                new OCTET_STRING(IV.getIV()));
+        EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
+                new BIT_STRING(key_data, 0));
+        EncryptedKey key = new EncryptedKey(encValue);
+        PKIArchiveOptions opt = new PKIArchiveOptions(key);
+
+        byte[] encoded = null;
+
+        //Let's make sure we can decode the encoded PKIArchiveOptions..
+        ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+
+        opt.encode(oStream);
+
+        encoded = oStream.toByteArray();
+        ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+        
+        @SuppressWarnings("unused")
+        PKIArchiveOptions options = (PKIArchiveOptions)
+                  (new PKIArchiveOptions.Template()).decode(inStream);
+
+        return encoded;
+    }
 }
 
 // START ENABLE_ECC
-- 
1.7.6.4

