>From bc0180feedcf561e53e3e56fe5014acf75dbdf09 Mon Sep 17 00:00:00 2001
From: Abhishek Koneru <akoneru@redhat.com>
Date: Thu, 27 Mar 2014 04:14:01 -0400
Subject: [PATCH] Refactoring KeyClient class and crypto classes.

---
 base/common/python/pki/key.py                      |  57 +++++---
 .../src/com/netscape/certsrv/key/KeyClient.java    | 147 +++++++++++----------
 .../com/netscape/certsrv/util/CryptoProvider.java  |  18 ++-
 .../netscape/certsrv/util/NSSCryptoProvider.java   |  31 ++++-
 base/kra/functional/drmtest.py                     |  22 +--
 .../src/com/netscape/cms/servlet/test/DRMTest.java |  87 ++++++------
 .../netscape/cms/servlet/key/KeyRequestDAO.java    |   2 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    |  38 ++++--
 8 files changed, 237 insertions(+), 165 deletions(-)

diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
index 69e01c852709d9745cf457042139d8a034d54fa6..64b4b9f41ab825e06fd24dea7fac82d9fd413362 100644
--- a/base/common/python/pki/key.py
+++ b/base/common/python/pki/key.py
@@ -52,8 +52,9 @@ class RequestId(object):
 #pylint: disable-msg=R0903
 class KeyData(object):
     '''
-    This is the object that contains the wrapped secret
-    when that secret is retrieved.
+    This is the object that contains the encoded wrapped secret
+    when that secret is retrieved. It is used by the DRM
+    to send information of the key in the key retrieval requests.
     '''
 
     # pylint: disable-msg=C0103
@@ -63,21 +64,32 @@ class KeyData(object):
         self.nonceData = None
         self.size = None
         self.wrappedPrivateData = None
-        
-        # To store the unwrapped key information.
-        # Is not transferred in the response.
-        self.private_data = None
 
     @classmethod
     def from_json(cls, attr_list):
         ''' Return a KeyData object from a JSON dict '''
         key_data = cls()
         for key in attr_list:
-            if (key == "wrappedPrivateData") or (key == "nonceData"):
-                setattr(key_data, key, base64.decodestring(attr_list[key]))
-            else:
-                setattr(key_data, key, attr_list[key])
+            setattr(key_data, key, attr_list[key])
         return key_data
+    
+class Key(object):
+    '''
+    An instance of this class stores the decoded encrypted secret
+    present in the KeyData object passed in the constructor.
+    All the key retrieval requests return this object.
+    '''
+    def __init__(self, key_data):
+        ''' Constructor '''
+        self.encrypted_data = base64.decodestring(key_data.wrappedPrivateData)
+        self.nonce_data = base64.decodestring(key_data.nonceData)
+        self.algorithm = key_data.algorithm
+        self.size = key_data.size
+        
+        # To store the unwrapped key information.
+        # The decryption takes place on the client side.
+        self.data = None
+
 
 class KeyInfo(object):
     '''
@@ -542,14 +554,14 @@ class KeyClient(object):
         algorithm_oid = self.DES_EDE3_CBC_OID
         symkey_params = base64.encodestring(nonce_iv)
 
-        return self.archive_wrapped_data(client_key_id, data_type, wrapped_private_data,
+        return self.archive_encrypted_data(client_key_id, data_type, wrapped_private_data,
                                          trans_wrapped_session_key, algorithm_oid,
                                          symkey_params, key_algorithm=key_algorithm,
                                          key_size=key_size)
 
     @pki.handle_exceptions()
-    def archive_wrapped_data(self, client_key_id, data_type,
-                    wrapped_private_data, trans_wrapped_session_key,
+    def archive_encrypted_data(self, client_key_id, data_type,
+                    encrypted_data, trans_wrapped_session_key,
                     algorithm_oid, symkey_params,
                     key_algorithm=None, key_size=None):
         ''' Archive a secret (symmetric key or passphrase) on the DRM.
@@ -580,12 +592,12 @@ class KeyClient(object):
                 raise TypeError(
                         "For symmetric keys, key algorithm and key size must be specified")
 
-        if (wrapped_private_data is None) or (trans_wrapped_session_key is None) or \
+        if (encrypted_data is None) or (trans_wrapped_session_key is None) or \
            (algorithm_oid is None)  or (symkey_params is None):
             raise TypeError("All data and wrapping parameters must be specified")
 
         twsk = base64.encodestring(trans_wrapped_session_key)
-        data = base64.encodestring(wrapped_private_data)
+        data = base64.encodestring(encrypted_data)
         request = KeyArchivalRequest(client_key_id=client_key_id,
                             data_type=data_type,
                             wrapped_private_data=data,
@@ -598,7 +610,7 @@ class KeyClient(object):
         return self.create_request(request)
 
     @pki.handle_exceptions()
-    def archive_options_data(self, client_key_id, data_type, pki_archive_options,
+    def archive_pki_options(self, client_key_id, data_type, pki_archive_options,
                     key_algorithm=None, key_size=None):
         ''' Archive a secret (symmetric key or passphrase) on the DRM.
 
@@ -671,7 +683,8 @@ class KeyClient(object):
         url = self.key_url + '/retrieve'
         key_request = json.dumps(data, cls=encoder.CustomTypeEncoder, sort_keys=True)
         response = self.connection.post(url, key_request, self.headers)
-        return KeyData.from_json(response.json())
+        key_data = KeyData.from_json(response.json())
+        return Key(key_data)
 
     @pki.handle_exceptions()
     def retrieve_key(self, key_id, trans_wrapped_session_key=None):
@@ -721,13 +734,13 @@ class KeyClient(object):
                         request_id=request_id,
                         trans_wrapped_session_key=base64.encodestring(trans_wrapped_session_key))
 
-        key_data = self.retrieve_key_data(request)
+        key = self.retrieve_key_data(request)
         if not key_provided:
-            key_data.private_data = self.crypto.symmetric_unwrap(
-                                key_data.wrappedPrivateData,
+            key.data = self.crypto.symmetric_unwrap(
+                                key.encrypted_data,
                                 session_key,
-                                nonce_iv=key_data.nonceData)
-        return key_data
+                                nonce_iv=key.nonce_data)
+        return key
 
     @pki.handle_exceptions()
     def retrieve_key_by_passphrase(self, key_id, passphrase=None,
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 68c70fb68e5c58673f4375f513647ad7359cfc84..a3382c3b98ebd977fb18966806040e5f1b1a6fb3 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -49,7 +49,7 @@ public class KeyClient extends Client {
     public KeyClient(PKIClient client, String subsystem) throws Exception {
         super(client, subsystem, "key");
         init();
-        this.crypto=client.getCrypto();
+        this.crypto = client.getCrypto();
     }
 
     public void init() throws URISyntaxException {
@@ -70,6 +70,7 @@ public class KeyClient extends Client {
      * The HEADER and FOOTER should be removed from the string.
      * HEADER - CertData.HEADER
      * FOOTER - CertData.FOOTER
+     *
      * @param transportCert
      */
     public void setTransportCert(String transportCert) {
@@ -247,7 +248,7 @@ public class KeyClient extends Client {
      * @param data -- A KeyArchivalRequest/KeyRecoveryRequest/SymKeyGenerationRequest object
      * @return A KeyRequestResponse object
      */
-    public KeyRequestResponse createRequest(ResourceMessage request) {
+    private KeyRequestResponse createRequest(ResourceMessage request) {
         if (request == null) {
             throw new IllegalArgumentException("A Request object must be specified.");
         }
@@ -303,14 +304,14 @@ public class KeyClient extends Client {
      * @param data -- a KeyRecoveryRequest containing the keyId of the
      *            secret being retrieved, the request_id of the approved recovery
      *            request and a wrapping mechanism.
-     * @return A KeyData object containing the wrapped secret.
+     * @return A Key object containing the wrapped secret.
      */
-    public KeyData retrieveKeyData(KeyRecoveryRequest data) {
+    public Key retrieveKeyData(KeyRecoveryRequest data) {
         if (data == null) {
             throw new IllegalArgumentException("A KeyRecoveryRequest object must be specified");
         }
         Response response = keyClient.retrieveKey(data);
-        return client.getEntity(response, KeyData.class);
+        return new Key(client.getEntity(response, KeyData.class));
     }
 
     /**
@@ -321,27 +322,27 @@ public class KeyClient extends Client {
      * key of the DRM transport certificate before being sent to the DRM.
      *
      * This method will call CryptoUtil methods to generate the session key and wrap it
-     * with the DRM transport cert. The function will return the KeyData object, but with the secret
-     * set to the variable privateData. (The decryption of the wrappedPrivateData is done
+     * with the DRM transport cert. The function will return the Key object, but with the secret
+     * set to the variable data. (The decryption of the encryptedData is done
      * on the client side i.e. the secret is not transmitted as it is by the server.)
      *
      * @param keyId -- key id for secret
-     * @return A KeyData object containing the unwrapped secret.
+     * @return A Key object containing the unwrapped secret (set to the attribute data).
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
-     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     *             CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
      */
-    public KeyData retrieveKey(KeyId keyId) throws Exception {
+    public Key retrieveKey(KeyId keyId) throws Exception {
         if (keyId == null) {
             throw new IllegalArgumentException("KeyId must be specified.");
         }
         SymmetricKey sessionKey = crypto.generateSessionKey();
         byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
 
-        KeyData data = retrieveKey(keyId, transWrappedSessionKey);
+        Key data = retrieveKey(keyId, transWrappedSessionKey);
 
-        data.setPrivateData(crypto.unwrapUsingSessionKey(
-                Utils.base64decode(data.getWrappedPrivateData()), sessionKey,
-                KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(data.getNonceData())));
+        data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey,
+                KeyRequestResource.DES3_ALGORITHM, data.getNonceData()));
 
         return data;
     }
@@ -360,16 +361,17 @@ public class KeyClient extends Client {
      *
      * @param keyId -- key id for secret
      * @param transWrappedSessionKey -- session key wrapped by the transport cert.
-     * @return A KeyData object containing the wrapped secret.
+     * @return A Key object containing the wrapped secret.
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
-     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     *             CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
      */
-    public KeyData retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws Exception{
+    public Key retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws Exception {
 
         if (keyId == null) {
             throw new IllegalArgumentException("KeyId must be specified.");
         }
-        if (transWrappedSessionKey == null){
+        if (transWrappedSessionKey == null) {
             throw new IllegalArgumentException("A transport cert wrapped session key cannot be null.");
         }
 
@@ -398,11 +400,12 @@ public class KeyClient extends Client {
      *
      * @param keyId -- key id of secret.
      * @param passphrase -- passphrase used to wrap the secret in the response.
-     * @return KeyData object with the secret wrapped with the passphrase.
+     * @return A Key object with the secret wrapped with the passphrase.
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
-     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     *             CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
      */
-    public KeyData retrieveKeyByPassphrase(KeyId keyId, String passphrase) throws Exception{
+    public Key retrieveKeyByPassphrase(KeyId keyId, String passphrase) throws Exception {
         if (keyId == null) {
             throw new IllegalArgumentException("KeyId must be specified.");
         }
@@ -412,7 +415,7 @@ public class KeyClient extends Client {
         SymmetricKey sessionKey = crypto.generateSessionKey();
         byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
         byte[] nonceData = CryptoUtil.getNonceData(8);
-        byte[] sessionWrappedPassphrase = crypto.wrapUsingSessionKey(passphrase, nonceData, sessionKey,
+        byte[] sessionWrappedPassphrase = crypto.wrapWithSessionKey(passphrase, nonceData, sessionKey,
                 KeyRequestResource.DES3_ALGORITHM);
 
         return retrieveKeyUsingWrappedPassphrase(keyId, transWrappedSessionKey, sessionWrappedPassphrase, nonceData);
@@ -431,11 +434,12 @@ public class KeyClient extends Client {
      * @param transWrappedSessionKey -- Session key wrapped with the transport cert
      * @param sessionWrappedPassphrase -- Passphrase wrapped with the session key
      * @param nonceData -- nonce data used for encryption.
-     * @return A KeyData object with the secret wrapped by the passphrase provided.
+     * @return A Key object with the secret wrapped by the passphrase provided.
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
-     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     *             CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
      */
-    public KeyData retrieveKeyUsingWrappedPassphrase(KeyId keyId, byte[] transWrappedSessionKey,
+    public Key retrieveKeyUsingWrappedPassphrase(KeyId keyId, byte[] transWrappedSessionKey,
             byte[] sessionWrappedPassphrase, byte[] nonceData) throws Exception {
 
         if (keyId == null) {
@@ -485,9 +489,9 @@ public class KeyClient extends Client {
      * @param keyId -- key id for secret
      * @param certificate -- the certificate associated with the private key
      * @param passphrase -- A passphrase for the pkcs12 file.
-     * @return A KeyData object with the wrapped secret
+     * @return A Key object with the wrapped secret
      */
-    public KeyData retrieveKeyByPKCS12(KeyId keyId, String certificate, String passphrase) {
+    public Key retrieveKeyByPKCS12(KeyId keyId, String certificate, String passphrase) {
         if (keyId == null || certificate == null || passphrase == null) {
             throw new IllegalArgumentException("KeyId, certificate and passphrase must be specified.");
         }
@@ -503,55 +507,61 @@ public class KeyClient extends Client {
     }
 
     /**
-     * Archive a secret (symmetric key or passphrase) on the DRM.
+     * Archive a passphrase on the DRM.
      *
      * Requires a user-supplied client ID. There can be only one active
      * key with a specified client ID. If a record for a duplicate active
      * key exists, a BadRequestException is thrown.
      *
-     * dataType can be one of the following:
-     * KeyClient.SYMMETRIC_KEY_TYPE,
-     * KeyClient.ASYMMETRIC_KEY_TYPE,
-     * KeyClient.PASS_PHRASE_TYPE
      *
      * @param clientKeyId -- Client Key Identfier
-     * @param dataType -- Type of the secret being archived.
-     * @param privateData -- the raw secret to be archived.
-     * @param keyAlgorithm
-     * @param keySize
-     *        keyAlgorithm and keySize are applicable to symmetric keys only.
-     *        If a symmetric key is being archived, these parameters are required.
+     * @param passphrase -- Secret passphrase to be archived
      * @return A KeyRequestResponse object with information about the request.
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
-     *         IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
-     *         BadPaddingException, IllegalBlockSizeException
+     *             IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
      */
-    public KeyRequestResponse archiveKey(String clientKeyId, String dataType, String privateData, String keyAlgorithm,
-            int keySize) throws Exception {
+    public KeyRequestResponse archivePassphrase(String clientKeyId, String passphrase) throws Exception {
 
-        if (clientKeyId == null || dataType == null) {
-            throw new IllegalArgumentException("Client key id and data type must be specified.");
-        }
-        if (dataType == KeyRequestResource.SYMMETRIC_KEY_TYPE) {
-            if (keyAlgorithm == null || keySize < 0) {
-                throw new IllegalArgumentException(
-                        "Key algorithm and key size must be specified for a symmetric key type request.");
-            }
-        }
-        if (privateData == null) {
-            throw new IllegalArgumentException("No data provided to archive. privateData must be specified.");
-        }
         // Default algorithm OID for DES_EDE3_CBC
         String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString();
         byte[] nonceData = CryptoUtil.getNonceData(8);
-        String symAlgParams = Utils.base64encode(nonceData);
         SymmetricKey sessionKey = crypto.generateSessionKey();
         byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
-        byte[] wrappedPrivateData = crypto.wrapUsingSessionKey(privateData, nonceData,
+        byte[] encryptedData = crypto.wrapWithSessionKey(passphrase, nonceData,
                 sessionKey, KeyRequestResource.DES3_ALGORITHM);
 
-        return archiveWrappedData(clientKeyId, dataType, keyAlgorithm, keySize, algorithmOID,
-                symAlgParams, wrappedPrivateData, transWrappedSessionKey);
+        return archiveEncryptedData(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, null, 0, algorithmOID,
+                nonceData, encryptedData, transWrappedSessionKey);
+    }
+
+    /**
+     * Archive a symmetric key on the DRM.
+     *
+     * Requires a user-supplied client ID. There can be only one active
+     * key with a specified client ID. If a record for a duplicate active
+     * key exists, a BadRequestException is thrown.
+     *
+     * @param clientKeyId -- Client Key Identifier
+     * @param keyAlgorithm -- Algorithm used by the symmetric key
+     * @param keySize -- Strength of the symmetric key (secret)
+     * @return A KeyRequestResponse object with information about the request.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *             IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *             BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyRequestResponse archiveSymmetricKey(String clientKeyId, SymmetricKey secret, String keyAlgorithm,
+            int keySize) throws Exception {
+
+        // Default algorithm OID for DES_EDE3_CBC
+        String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString();
+        SymmetricKey sessionKey = crypto.generateSessionKey();
+        byte[] nonceData = CryptoUtil.getNonceData(8);
+        byte[] encryptedData = crypto.wrapWithSessionKey(secret, sessionKey, nonceData);
+        byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+
+        return archiveEncryptedData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, keyAlgorithm, keySize,
+                algorithmOID, nonceData, encryptedData, transWrappedSessionKey);
     }
 
     /**
@@ -565,15 +575,16 @@ public class KeyClient extends Client {
      * @param dataType -- Type of secret being archived
      * @param keyAlgorithm -- Algorithm used - if the secret is a symmetric key
      * @param keySize -- Strength of the symmetric key (secret)
-     * @param algorithmOID -- string for the symmetric key wrap
+     * @param algorithmOID -- OID of the algorithm used for the symmetric key wrap
      * @param symAlgParams -- storing the value of Utils.base64encode(nonceData)
-     * @param wrappedPrivateData -- which is the secret wrapped by a session
-     *                              key (168 bit 3DES symmetric key)
+     * @param encryptedData -- which is the secret wrapped by a session
+     *            key (168 bit 3DES symmetric key)
      * @param transWrappedSessionKey -- session key wrapped by the transport cert.
      * @return A KeyRequestResponse object with information about the request.
      */
-    public KeyRequestResponse archiveWrappedData(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
-            String algorithmOID, String symAlgParams, byte[] wrappedPrivateData, byte[] transWrappedSessionKey) {
+    public KeyRequestResponse archiveEncryptedData(String clientKeyId, String dataType, String keyAlgorithm,
+            int keySize,
+            String algorithmOID, byte[] nonceData, byte[] encryptedData, byte[] transWrappedSessionKey) {
 
         if (clientKeyId == null || dataType == null) {
             throw new IllegalArgumentException("Client key id and data type must be specified.");
@@ -584,8 +595,8 @@ public class KeyClient extends Client {
                         "Key algorithm and key size must be specified for a symmetric key type request.");
             }
         }
-        if (wrappedPrivateData == null || transWrappedSessionKey == null || algorithmOID == null
-                || symAlgParams == null) {
+        if (encryptedData == null || transWrappedSessionKey == null || algorithmOID == null
+                || nonceData == null) {
             throw new IllegalArgumentException("All data and wrapping parameters must be specified.");
         }
         KeyArchivalRequest data = new KeyArchivalRequest();
@@ -595,8 +606,8 @@ public class KeyClient extends Client {
         data.setKeySize(keySize);
         data.setClientKeyId(clientKeyId);
         data.setAlgorithmOID(algorithmOID);
-        data.setSymmetricAlgorithmParams(symAlgParams);
-        String req1 = Utils.base64encode(wrappedPrivateData);
+        data.setSymmetricAlgorithmParams(Utils.base64encode(nonceData));
+        String req1 = Utils.base64encode(encryptedData);
         data.setWrappedPrivateData(req1);
         data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
 
@@ -615,7 +626,7 @@ public class KeyClient extends Client {
      * @return A KeyRequestResponse object with information about the request.
      * @throws Exception
      */
-    public KeyRequestResponse archiveOptionsData(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
+    public KeyRequestResponse archivePKIOptions(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
             byte[] pkiArchiveOptions) {
 
         if (clientKeyId == null || dataType == null) {
diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
index f5e5603aa8f8a35fe92701d10560e802e290bebb..d0c753ae0d57e9bf8c229486db2745b10e970600 100644
--- a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
@@ -2,6 +2,13 @@ package com.netscape.certsrv.util;
 
 import org.mozilla.jss.crypto.SymmetricKey;
 
+/**
+ * An abstract class defining the functionality to be provided by
+ * sub classes to perform cryptographic operations.
+ *
+ * @author akoneru
+ *
+ */
 public abstract class CryptoProvider {
 
     public abstract void initialize() throws Exception;
@@ -13,13 +20,18 @@ public abstract class CryptoProvider {
     public abstract byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert)
             throws Exception;
 
-    public abstract byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm)
+    public abstract byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm)
             throws Exception;
 
-    public abstract String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+    public abstract byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv) throws Exception;
+
+    public abstract byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
             String keyAlgorithm, byte[] nonceData) throws Exception;
 
-    public abstract String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+    public abstract byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase)
             throws Exception;
 
+    public abstract byte[] createPKIArchiveOptions(String transportCert, SymmetricKey secret, String passphrase,
+            String keyAlgorithm, int symKeySize, byte[] nonceData) throws Exception;
+
 }
diff --git a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
index ae4e0d168aea2f31a476a8a6b33effa27995e902..7c20e5cf45a64c7608dfaa3ab25a7e30ebc7f0e5 100644
--- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
@@ -1,17 +1,25 @@
 package com.netscape.certsrv.util;
 
+import java.io.CharConversionException;
 import java.io.File;
+import java.io.IOException;
 import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
 
 import org.mozilla.jss.CertDatabaseException;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.CryptoManager.NotInitializedException;
 import org.mozilla.jss.KeyDatabaseException;
+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.EncryptionAlgorithm;
 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.TokenException;
@@ -119,7 +127,7 @@ public class NSSCryptoProvider extends CryptoProvider {
     }
 
     @Override
-    public byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm)
+    public byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm)
             throws Exception {
         if (token == null) {
             throw new NotInitializedException();
@@ -129,7 +137,7 @@ public class NSSCryptoProvider extends CryptoProvider {
     }
 
     @Override
-    public String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+    public byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
             String encryptionAlgorithm, byte[] nonceData) throws Exception {
         if (token == null) {
             throw new NotInitializedException();
@@ -140,7 +148,7 @@ public class NSSCryptoProvider extends CryptoProvider {
     }
 
     @Override
-    public String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) throws Exception {
+    public byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase) throws Exception {
         return CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
     }
 
@@ -201,4 +209,21 @@ public class NSSCryptoProvider extends CryptoProvider {
         return alg;
     }
 
+    @Override
+    public byte[] createPKIArchiveOptions(String transportCert, SymmetricKey secret, String passphrase,
+            String keyAlgorithm, int symKeySize, byte[] nonceData) throws InvalidKeyException,
+            CertificateEncodingException, CharConversionException, NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException, IllegalStateException, TokenException, IOException,
+            IllegalBlockSizeException, BadPaddingException, InvalidBERException {
+
+        return CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, secret, passphrase,
+                getKeyGenAlgorithm(keyAlgorithm), symKeySize, new IVParameterSpec(nonceData));
+    }
+
+    @Override
+    public byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv)
+            throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException {
+        return CryptoUtil.wrapSymmetricKey(token, secret, sessionKey, new IVParameterSpec(iv));
+    }
+
 }
diff --git a/base/kra/functional/drmtest.py b/base/kra/functional/drmtest.py
index 268c50913a44584216dc4c0736dba09958eaf257..b6fa18dcb2b7f6f8efe1040b1c9be2526762e37f 100644
--- a/base/kra/functional/drmtest.py
+++ b/base/kra/functional/drmtest.py
@@ -54,14 +54,14 @@ def print_key_info(key_info):
     print "Owner Name: " + str(key_info.ownerName)
     print "Size: " + str(key_info.size)
 
-def print_key_data(key_data):
+def print_key_data(key):
     ''' Prints the relevant fields of a KeyData object '''
-    print "Key Algorithm: " + str(key_data.algorithm)
-    print "Key Size: " + str(key_data.size)
-    print "Nonce Data: " + base64.encodestring(key_data.nonceData)
-    print "Wrapped Private Data: " + base64.encodestring(key_data.wrappedPrivateData)
-    if key_data.private_data is not None:
-        print "Private Data: " + base64.encodestring(key_data.private_data)
+    print "Key Algorithm: " + str(key.algorithm)
+    print "Key Size: " + str(key.size)
+    print "Nonce Data: " + base64.encodestring(key.nonce_data)
+    print "Wrapped Private Data: " + base64.encodestring(key.encrypted_data)
+    if key.data is not None:
+        print "Private Data: " + base64.encodestring(key.data)
 
 def main():
     ''' test code execution '''
@@ -139,15 +139,15 @@ def main():
     print "My key id is " + str(key_id)
     key_data = keyclient.retrieve_key(key_id, trans_wrapped_session_key=wrapped_session_key)
     print_key_data(key_data)
-    unwrapped_key = crypto.symmetric_unwrap(key_data.wrappedPrivateData,
+    unwrapped_key = crypto.symmetric_unwrap(key_data.encrypted_data,
                                             session_key,
-                                            nonce_iv=key_data.nonceData)
+                                            nonce_iv=key_data.nonce_data)
     key1 = base64.encodestring(unwrapped_key)
 
     # Test 7: Recover key without providing trans_wrapped_session_key
     key_data = keyclient.retrieve_key(key_id)
     print_key_data(key_data)
-    key2 = base64.encodestring(key_data.private_data)
+    key2 = base64.encodestring(key_data.data)
 
     # Test 8 - Confirm that keys returned are the same
     if key1 == key2:
@@ -233,7 +233,7 @@ def main():
 
     key_data = keyclient.retrieve_key(key_info.get_key_id())
     print_key_data(key_data)
-    key2 = base64.encodestring(key_data.private_data)
+    key2 = base64.encodestring(key_data.data)
 
     if key1 == key2:
         print "Success: archived and recovered keys match"
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index 3fc2984a90acc1343f647fc005b22c47ea04c446..cb80039b76d642586b0f14bcd3c756ebf67cd44c 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -40,8 +40,8 @@ import com.netscape.certsrv.cert.CertData;
 import com.netscape.certsrv.client.ClientConfig;
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.key.Key;
 import com.netscape.certsrv.key.KeyClient;
-import com.netscape.certsrv.key.KeyData;
 import com.netscape.certsrv.key.KeyInfo;
 import com.netscape.certsrv.key.KeyRequestInfo;
 import com.netscape.certsrv.key.KeyRequestInfoCollection;
@@ -148,13 +148,13 @@ public class DRMTest {
         String passphrase = null;
 
         // Session keys and passphrases for recovery
-        SymmetricKey recoveryKey = null;
+        SymmetricKey sessionKey = null;
         byte[] wrappedRecoveryKey = null;
         String recoveryPassphrase = null;
         byte[] wrappedRecoveryPassphrase = null;
 
         // retrieved data (should match archived data)
-        String wrappedRecoveredKey = null;
+        byte[] encryptedData = null;
         String recoveredKey = null;
 
         // various ids used in recovery/archival operations
@@ -164,7 +164,7 @@ public class DRMTest {
 
         // Variables for data structures from calls
         KeyRequestResponse requestResponse = null;
-        KeyData keyData = null;
+        Key keyData = null;
         KeyInfo keyInfo = null;
 
         // Initialize token
@@ -239,15 +239,14 @@ public class DRMTest {
         clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
         try {
             vek = nssCrypto.generateSessionKey();
-            byte[] encoded = CryptoUtil.createPKIArchiveOptions(nssCrypto.getManager(), nssCrypto.getToken(),
-                    transportCert, vek, null,
-                    KeyGenAlgorithm.DES3, 0, new IVParameterSpec(iv));
+            byte[] encoded = nssCrypto.createPKIArchiveOptions(transportCert, vek, null,
+                    KeyRequestResource.DES3_ALGORITHM, 0, iv);
 
-            KeyRequestResponse info = keyClient.archiveOptionsData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
+            KeyRequestResponse info = keyClient.archivePKIOptions(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
                     KeyRequestResource.DES3_ALGORITHM, 0, encoded);
             log("Archival Results:");
             printRequestInfo(info.getRequestInfo());
-            keyId = info.getRequestInfo().getKeyId();
+            keyId = info.getKeyId();
         } catch (Exception e) {
             log("Exception in archiving symmetric key:" + e.getMessage());
             e.printStackTrace();
@@ -274,20 +273,20 @@ 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 = nssCrypto.generateSessionKey();
+            sessionKey = nssCrypto.generateSessionKey();
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(nssCrypto.getManager(), nssCrypto.getToken(),
-                    transportCert, recoveryKey);
+                    transportCert, sessionKey);
             keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
 
         try {
-            recoveredKey = new String(Utils.base64decode(nssCrypto.unwrapUsingSessionKey(
-                    Utils.base64decode(wrappedRecoveredKey), recoveryKey,
-                    KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(keyData.getNonceData()))));
+            recoveredKey = Utils.base64encode(nssCrypto.unwrapWithSessionKey(
+                    encryptedData, sessionKey,
+                    KeyRequestResource.DES3_ALGORITHM, keyData.getNonceData()));
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -304,10 +303,10 @@ public class DRMTest {
         recoveryPassphrase = "Gimme me keys please";
 
         try {
-            recoveryKey = nssCrypto.generateSessionKey();
-            wrappedRecoveryPassphrase = nssCrypto.wrapUsingSessionKey(recoveryPassphrase, iv, recoveryKey,
+            sessionKey = nssCrypto.generateSessionKey();
+            wrappedRecoveryPassphrase = nssCrypto.wrapWithSessionKey(recoveryPassphrase, iv, sessionKey,
                     KeyRequestResource.DES3_ALGORITHM);
-            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert);
+            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
 
             keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase,
                     iv);
@@ -316,10 +315,10 @@ public class DRMTest {
             e.printStackTrace();
         }
 
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
 
         try {
-            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+            recoveredKey = Utils.base64encode(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase));
         } catch (Exception e) {
             log("Error: unable to unwrap key using passphrase");
             e.printStackTrace();
@@ -335,12 +334,11 @@ public class DRMTest {
         // Test 8: Generate and archive a passphrase
         clientKeyId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
         try {
-            requestResponse = keyClient.archiveKey(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, passphrase, null,
-                    0);
+            requestResponse = keyClient.archivePassphrase(clientKeyId, passphrase);
 
             log("Archival Results:");
             printRequestInfo(requestResponse.getRequestInfo());
-            keyId = requestResponse.getRequestInfo().getKeyId();
+            keyId = requestResponse.getKeyId();
         } catch (Exception e) {
             log("Exception in archiving symmetric key:" + e.toString());
             e.printStackTrace();
@@ -365,17 +363,16 @@ public class DRMTest {
 
         // Test 10: Submit a recovery request for the passphrase using a session key
         log("Submitting a recovery request for the passphrase using session key");
-        recoveryKey = null;
+        sessionKey = null;
         wrappedRecoveryKey = null;
         try {
             keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase);
         } catch (Exception e) {
             log("Exception in recovering passphrase using session key: " + e.getMessage());
         }
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
         try {
-            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
-            recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+            recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8");
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -389,9 +386,9 @@ public class DRMTest {
 
         // Test 11: Submit a recovery request for the passphrase using a passphrase
         try {
-            recoveryKey = nssCrypto.generateSessionKey();
-            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert);
-            wrappedRecoveryPassphrase = nssCrypto.wrapUsingSessionKey(recoveryPassphrase, iv, recoveryKey,
+            sessionKey = nssCrypto.generateSessionKey();
+            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+            wrappedRecoveryPassphrase = nssCrypto.wrapWithSessionKey(recoveryPassphrase, iv, sessionKey,
                     KeyRequestResource.DES3_ALGORITHM);
             keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase,
                     iv);
@@ -400,10 +397,9 @@ public class DRMTest {
             System.out.println("Test 17: " + e1.getMessage());
             System.exit(-1);
         }
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
         try {
-            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
-            recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+            recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8");
         } catch (Exception e) {
             log("Error: cannot unwrap key using passphrase");
             e.printStackTrace();
@@ -422,10 +418,9 @@ public class DRMTest {
         } catch (Exception e1) {
             e1.printStackTrace();
         }
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
         try {
-            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
-            recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+            recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8");
         } catch (Exception e) {
             log("Error: Can't unwrap recovered key using passphrase");
             e.printStackTrace();
@@ -516,7 +511,7 @@ public class DRMTest {
                 KeyRequestResource.AES_ALGORITHM,
                 128, usages, null);
         printRequestInfo(genKeyResponse.getRequestInfo());
-        keyId = genKeyResponse.getRequestInfo().getKeyId();
+        keyId = genKeyResponse.getKeyId();
 
         // test 19: Get keyId for active key with client ID
         log("Getting key ID for symmetric key");
@@ -538,19 +533,19 @@ public class DRMTest {
         // Test 20: 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 = nssCrypto.generateSessionKey();
-            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert);
+            sessionKey = nssCrypto.generateSessionKey();
+            wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
             keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        encryptedData = keyData.getEncryptedData();
 
         try {
-            recoveredKey = new String(Utils.base64decode(nssCrypto.unwrapUsingSessionKey(
-                    Utils.base64decode(wrappedRecoveredKey), recoveryKey, KeyRequestResource.DES3_ALGORITHM,
-                    Utils.base64decode(keyData.getNonceData()))));
+            recoveredKey = new String(nssCrypto.unwrapWithSessionKey(
+                    encryptedData, sessionKey, KeyRequestResource.DES3_ALGORITHM,
+                    keyData.getNonceData()));
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -587,11 +582,11 @@ public class DRMTest {
                     transportCert, vek, null,
                     KeyGenAlgorithm.DES3, 0, new IVParameterSpec(iv));
 
-            KeyRequestResponse response = keyClient.archiveOptionsData(clientKeyId,
+            KeyRequestResponse response = keyClient.archivePKIOptions(clientKeyId,
                     KeyRequestResource.SYMMETRIC_KEY_TYPE, KeyRequestResource.AES_ALGORITHM, 128, encoded);
             log("Archival Results:");
             printRequestInfo(response.getRequestInfo());
-            keyId = response.getRequestInfo().getKeyId();
+            keyId = response.getKeyId();
         } catch (Exception e) {
             log("Exception in archiving symmetric key:" + e.getMessage());
             e.printStackTrace();
@@ -626,7 +621,7 @@ public class DRMTest {
         // generates a session key, wraps it with transport cert and completes the request.
         // The encrypted data is then unwrapped using the temporary session key and set to
         // the attribute privateData.
-        recoveredKey = keyData.getPrivateData();
+        recoveredKey = Utils.base64encode(keyData.getData());
 
         if (!recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
             log("Error: recovered and archived keys do not match!");
diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
index f72c4c78bc37c952cc015afde247710a02963108..0202af4bc38272ea5c618ed8e5f2de8d8002b585 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
@@ -169,7 +169,7 @@ public class KeyRequestDAO extends CMSRequestDAO {
         boolean keyExists = doesKeyExist(clientKeyId, "active");
 
         if (keyExists == true) {
-            throw new EBaseException("Can not archive already active existing key!");
+            throw new BadRequestException("Can not archive already active existing key!");
         }
 
         IRequest request = queue.newRequest(IRequest.SECURITY_DATA_ENROLLMENT_REQUEST);
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index d3eafd7f5e1eadba0a2cefd56c120e7495567e4d..ee077872ff140726a5c65d11435a806ddd9e021f 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -1551,12 +1551,11 @@ public class CryptoUtil {
         return iv;
     }
 
-    public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+    public static byte[] unwrapUsingPassphrase(byte[] 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")
@@ -1566,20 +1565,16 @@ public class CryptoUtil {
         PasswordConverter passConverter = new
                     PasswordConverter();
 
-        byte[] encoded = Utils.base64decode(wrappedRecoveredKey);
-
-        ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+        ByteArrayInputStream inStream = new ByteArrayInputStream(wrappedRecoveredKey);
         cInfo = (EncryptedContentInfo)
                       new EncryptedContentInfo.Template().decode(inStream);
 
         byte[] decodedData = cInfo.decrypt(pass, passConverter);
 
-        unwrappedData = Utils.base64encode(decodedData);
-
-        return unwrappedData;
+        return decodedData;
     }
 
-    public static String unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
+    public static byte[] unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
             SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException,
             BadPaddingException,
             IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
@@ -1587,9 +1582,8 @@ public class CryptoUtil {
         Cipher decryptor = token.getCipherContext(alg);
         decryptor.initDecrypt(recoveryKey, IV);
         byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
-        String unwrappedS = Utils.base64encode(unwrappedData);
 
-        return unwrappedS;
+        return unwrappedData;
     }
 
     public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk,
@@ -1622,6 +1616,28 @@ public class CryptoUtil {
         return session_data;
     }
 
+    /**
+     * Wrap a symmetric Key with a SymmetricKey
+     *
+     * @param token
+     * @param secret
+     * @param wrapper
+     * @return
+     * @throws TokenException
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidAlgorithmParameterException
+     * @throws InvalidKeyException
+     */
+    public static byte[] wrapSymmetricKey(CryptoToken token, SymmetricKey secret, SymmetricKey wrapper,
+            IVParameterSpec IV) throws NoSuchAlgorithmException, TokenException, InvalidKeyException,
+            InvalidAlgorithmParameterException {
+        KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+        wrapper1.initWrap(wrapper, IV);
+        byte[] keyData = wrapper1.wrap(secret);
+
+        return keyData;
+    }
+
     public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
             SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) throws TokenException,
             CharConversionException,
-- 
1.8.5.3

