From: Holger Dengler <hd@linux.vnet.ibm.com>
Subject: libica: Support for MSA4 extension, part 2
Patch-mainline: v2.2.0
Git-commit: 691ae503c2679c1bf79095bff793591675686f4c
Git-repo: git://opencryptoki.git.sourceforge.net/gitroot/opencryptoki/libica
References: FATE#314078

Summary:     libica: Support for MSA4 extension, part 2
Description: Introduce support for MSA4 extension. New modes of operation
             for symetric block ciphers:
                CMAC (DES, TDES)
                CMAC chaining for all ciphers
                CBC-CS (DES, TDES, AES-128, AES-192, and AES-256)
                CCM (AES-128, AES-192, and AES-256)
                GCM (AES-128, AES-192, and AES-256)

Signed-off-by: Holger Dengler <hd@linux.vnet.ibm.com>
--- a/include/ica_api.h
+++ b/include/ica_api.h
@@ -87,6 +87,16 @@ typedef ica_adapter_handle_t ICA_ADAPTER
 #define MODE_OFB 		4
 #define MODE_CTR 		5
 #define MODE_XTS 		6
+#define MODE_GCM		7
+#define MODE_CBCCS		8
+#define MODE_CCM		9
+
+/**
+ * CBC Ciphertext Stealing variants
+ */
+#define ICA_CBCCS_VARIANT1	1
+#define ICA_CBCCS_VARIANT2	2
+#define ICA_CBCCS_VARIANT3	3
 
 /**
  * @deprecated
@@ -1698,6 +1708,68 @@ unsigned int ica_des_cbc(const unsigned
 			 unsigned int direction);
 
 /**
+ * Encrypt or decrypt data with an DES key using Cipher Block Chaining with
+ * Ciphertext Stealing (CBC-CS) mode as described in NIST Special Publication
+ * 800-38A Chapter 6.2 and the Addendum to NIST Special Publication 800-38A on
+ * Recommendation for Block Cipher Modes of Operation: Three Variants of
+ * Ciphertext Stealing for CBC Moder:
+ * ica_des_cbc_cs may be used to encrypt or decrypt the last chunk of a
+ * message consisting of multiple chunks where all but the last chunk are
+ * encrypted or decrypted by chained calls to ica_des_cbc and the resulting
+ * iv of the last call to ica_des_cbc is fed into the iv of the ica_des_cbc_cs
+ * call provided the chunk is greater than cipher block size (greater than
+ * 8 bytes for DES).
+ *
+ * Required HW Support
+ * KMC-DEA
+ *
+ * @param in_data
+ * Pointer to a readable buffer, that contains the message to be en/decrypted.
+ * The size of the message in bytes is data_length. The size of this buffer
+ * in bytes must be at least as big as data_length.
+ * @param out_data
+ * Pointer to a writable buffer, that will contain the resulting en/decrypted
+ * message. The size of this buffer in bytes must be at least as big as
+ * data_length.
+ * @param data_length
+ * Length in bytes of the message to be en/decrypted, which resides at the
+ * beginning of in_data. data_length must be greater than or equal to the
+ * cipher block size (i.e. a multiple of 8 bytes for DES).
+ * @param key
+ * Pointer to a valid DES key of 8 bytes length.
+ * @param iv
+ * Pointer to a valid initialization vector of cipher block size bytes.
+ * This vector will be overwritten during the function. For variant equals 1
+ * or variant equals 2 the result value in iv may be used as initialization
+ * vector for a chained ica_des_cbc call with the same key if data_length is
+ * a multiple of the cipher block size.
+ * @param direction
+ * 0 or 1:
+ * 0 Use the decrypt function.
+ * 1 Use the encrypt function.
+ * @param variant
+ * 1 Use variant CBC-CS1 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: keep last two blocks in order.
+ * 2 Use variant CBC-CS2 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: switch order of the last two blocks
+ *   if data_length is not a multiple of the cipher block size (i.e. a
+ *   multiple of 8 for DES).
+ * 3 Use variant CBC-CS3 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: always switch order of the last two
+ *   blocks.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_des_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			    unsigned long data_length, const unsigned char *key,
+			    unsigned char *iv,
+			    unsigned int direction,
+			    unsigned int variant);
+
+/**
  * Encrypt or decrypt data with an DES key using Cipher Feedback (CFB) mode as
  * described in NIST Special Publication 800-38A Chapter 6.3.
  *
@@ -1884,6 +1956,152 @@ unsigned int ica_des_ofb(const unsigned
 			 unsigned char *iv, unsigned int direction);
 
 /**
+ * Authenticate data or verify the authenticity of data with an DES key using
+ * the Block Cipher Based Message Authetication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B. ica_des_cmac can be used to
+ * authenticate or verify the authenticity of a complete message.
+ *
+ * Required HW Support
+ * KMAC-DEA
+ * PCC-Compute-Last_block-CMAC-Using-DEA
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a message  to be authenticated or of which the
+ * authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message to be authenticated or verified.
+ * @param mac
+ * Pointer to a buffer of size greater than or equal to mac_length bytes. If
+ * direction is 1 the buffer must be writable and a message authentication code
+ * for the message in message of size mac_length bytes will be written to the
+ * buffer. If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the message in message.
+ * @param mac_length
+ * Length in bytes of the message authentication code mac in bytes that is less
+ * than or equal to the cipher block size (i.e. 8 bytes for DES). It is
+ * recommended to use values greater than or equal to 8.
+ * @param key
+ * Pointer to a valid DES key of 8 bytes length.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code
+ * 1 Compute message authentication code for the message
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_des_cmac(const unsigned char *message, unsigned long message_length,
+			  unsigned char *mac, unsigned int mac_length,
+			  const unsigned char *key,
+			  unsigned int direction);
+
+/**
+ * Authenticate data or verify the authenticity of data with an DES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B.
+ * ica_des_cmc_intermediate and ica_des_cmac_last can be used when the message
+ * to be authenticated or to be verfied using CMAC is supplied in multiple
+ * chunks. ica_des_cmac_intermediate is used to process all but the last
+ * chunk. All message chunks to preprocessed by ica_des_cmac_intermediate
+ * must have a size that is a multiple of the cipher block size (i.e a
+ * multiple of 8 bytes for DES).
+ * Note: ica_des_cmac_intermediate has no direction argument it can be used
+ * during an authentication and during authenticity verification.
+ *
+ * Required HW Support
+ * KMAC-DEA
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to
+ * message_length bytes. It contains a non final part of a message which
+ * shall be authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message part in message. It must be a multiple
+ * of the cipher block size.
+ * @param key
+ * Pointer to a valid DES key of 8 bytes length.
+ * @param iv
+ * Pointer to a valid  initialization vector of size cipher block size (i.e.
+ * 8 bytes for DES). For the first message part it must be set to a string
+ * of zeros. For processing the n-th message part it must be the resulting iv
+ * value of the ica_des_cmac_intermediate applied to the (n-1)-th message
+ * part. This vector will be overwritten during the function. The result value
+ * in iv may be used as initialization vector for a chained call to
+ * ica_des_cmac_initermediate or to ica_des_cmac_last with the same key.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_des_cmac_intermediate(const unsigned char *message,
+				       unsigned long message_length,
+				       const unsigned char *key,
+				       unsigned char *iv);
+
+/**
+ * Authenticate data or verify the authenticity of data with an DES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B.
+ * ica_des_cmac_last can be used to authenticate or verify the authenticity of
+ * a complete message or of the final part of a message for which all
+ * preceding parts were preprocessed with ica_des_cmac_intermediate.
+ *
+ * Required HW Support
+ * KMAC-DEA,
+ * PCC-Compute-Last_block-CMAC-Using-DEA
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a message or the final part of a message to be
+ * authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message to be authenticated or verified.
+ * @param mac
+ * Pointer to a buffer of size greater than or equal to mac_length bytes.
+ * If direction is 1 the buffer must be writable and a message authentication
+ * code for the message in message of size mac_length bytes will be written to
+ * the buffer.
+ * If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the message in message.
+ * @param mac_length
+ * Length in bytes of the message authentication code mac in bytes that is less
+ * than or equal to the cipher block size (i.e. 8 bytes for DES). It is
+ * recommended to use values greater than or equal to 8.
+ * @param key
+ * Pointer to a valid DES key of 8 bytes length.
+ * @param iv
+ * Pointer to a valid initialization vector of size cipher block size. If iv is
+ * NULL message is assumed to be the complete message to be processed.
+ * Otherwise message is the final part of a composite message to be processed
+ * and iv contains the output vector resulting from processing all previous
+ * parts with chained calls to ica_aes_cmac_intermediate, i.e. the value
+ * returned in iv of the ica_des_cmac_intermediate call applied to the
+ * penultimate message part.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code
+ * 1 Compute message authentication code for the message
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_des_cmac_last(const unsigned char *message, unsigned long message_length,
+			       unsigned char *mac, unsigned int mac_length,
+			       const unsigned char *key,
+			       unsigned char *iv,
+			       unsigned int direction);
+
+/**
  * Encrypt or decrypt data with an 3DES key using Electronic Cook Book (ECB)
  * mode as described in NIST Special Publication 800-38A Chapter 6.1.
  *
@@ -1958,6 +2176,68 @@ unsigned int ica_3des_cbc(const unsigned
 			  unsigned int direction);
 
 /**
+ * Encrypt or decrypt data with an 3DES key using Cipher Block Chaining with
+ * Ciphertext Stealing (CBC-CS) mode as described in NIST Special Publication
+ * 800-38A Chapter 6.2 and the Addendum to NIST Special Publication 800-38A on
+ * "Recommendation for Block Cipher Modes of Operation: Three Variants of
+ * Ciphertext Stealing for CBC Mode":
+ * ica_3des_cbc_cs may be used to encrypt o decrypt the last chunk of a
+ * message consisting of multiple chunks where all but the last chunk are
+ * encrypted or decrypted by chained calls to ica_3des_cbc and the resulting
+ * iv of the last call to ica_3des_cbc is fed into the iv of the
+ * ica_3des_cbc_cs call provided the chunc is greater than cipher block size
+ * (greater than 8 bytes for 3DES).
+ *
+ * Required HW Support
+ * KMC-TDEA-192
+ *
+ * @param in_data
+ * Pointer to a readable buffer, that contains the message to be en/decrypted.
+ * The size of the message in bytes is data_length. The size of this buffer
+ * in bytes must be at least as big as data_length.
+ * @param out_data
+ * Pointer to a writable buffer, that will contain the resulting en/decrypted
+ * message. The size of this buffer in bytes must be at least as big as
+ * data_length.
+ * @param data_length
+ * Length in bytes of the message to be en/decrypted, which resides at the
+ * beginning of in_data. data_length must be greater than or equal to the
+ * cipher block size (i.e. a multiple of 8 bytes for 3DES).
+ * @param key
+ * Pointer to a valid 3DES key of 24 bytes length.
+ * @param iv
+ * Pointer to a valid initialization vector of cipher block size bytes. This
+ * vector will be overwritten during the function. For variant equals 1 or
+ * variant equals 2 the result value in iv may be used as initialization vector
+ * for a chained ica_3des_cbc call with the same key if data_length is a
+ * multiple of the cipher block size.
+ * @param direction
+ * 0 or 1:
+ * 0 Use the decrypt function.
+ * 1 Use the encrypt function.
+ * @param variant
+ * 1 Use variant CBC-CS1 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: keep last two blocks in order.
+ * 2 Use variant CBC-CS2 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: switch order of the last two blocks
+ *   if data_length is not a multiple of the cipher block size (i.e. a
+ *   multiple of 8 for DES).
+ * 3 Use variant CBC-CS3 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: always switch order of the last two
+ *   blocks.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_3des_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			     unsigned long data_length,
+			     const unsigned char *key,
+			     unsigned char *iv,
+			     unsigned int direction, unsigned int variant);
+
+/**
  * Encrypt or decrypt data with an 3DES key using Cipher Feedback (CFB) mode as
  * described in NIST Special Publication 800-38A Chapter 6.3.
  *
@@ -2145,6 +2425,152 @@ unsigned int ica_3des_ofb(const unsigned
 			  unsigned char *iv, unsigned int direction);
 
 /**
+ * Authenticate data or verify the authenticity of data with an 3DES key
+ * using the Block Cipher Based Message Authetication Code (CMAC) mode as
+ * described in NIST Special Publication 800-38B.
+ * ica_3des_cmac can be used to authenticate or verify the authenticity of a
+ * complete message.
+ *
+ * Required HW Support
+ * KMAC-TDEA-192
+ * PCC-Compute-Last_block-CMAC-Using-TDEA-192
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to
+ * message_length bytes. It contains a message  to be authenticated or of
+ * which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message to be authenticated or verified.
+ * @param mac
+ * Pointer to a buffer of size greater than or equal to mac_length bytes.
+ * If direction is 1 the buffer must be writable and a message authentication
+ * code for the message in message of size mac_length bytes will be written to
+ * the buffer.
+ * If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the message in message.
+ * @param mac_length
+ * Length in bytes of the message authentication code mac in bytes that is less
+ * than or equal to the cipher block size (i.e. 8 bytes for TDES). It is
+ * recommended to use values greater than or equal to 8.
+ * @param key
+ * Pointer to a valid 3DES key of 24 bytes length.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code
+ * 1 Compute message authentication code for the message
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_3des_cmac(const unsigned char *message, unsigned long message_length,
+			   unsigned char *mac, unsigned int mac_length,
+			   const unsigned char *key,
+			   unsigned int direction);
+
+/**
+ * Authenticate data or verify the authenticity of data with an 3DES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B.
+ * ica_3des_cmc_intermediate and ica_3des_cmac_last can be used when the
+ * message to be authenticated or to be verfied using CMAC is supplied in
+ * multiple chunks. ica_3des_cmac_intermediate is used to process all but the
+ * last chunk. All message chunks to preprocessed by
+ * ica_3des_cmac_intermediate must have a size that is a multiple of the
+ * cipher block size (i.e a multiple of 8 bytes for 3DES).
+ * Note: ica_3des_cmac_intermediate has no direction argument it can be used
+ * during an authentication and during authenticity verification.
+ *
+ * Required HW Support
+ * KMAC-TDEA-192,
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a non final part of a message which shall be
+ * authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message part in message. It must be a multiple of the
+ * cipher block size.
+ * @param key
+ * Pointer to a valid 3DES key of 24 bytes length.
+ * @param iv
+ * Pointer to a valid initialization vector of size cipher block size
+ * (i.e. 8 bytes for 3DES). For the first message part it must be set to a
+ * string of zeros. For processing the n-th message part it must be the
+ * resulting iv value of the ica_3des_cmac_intermediate applied to the
+ * (n-1)-th message part. This vector will be overwritten during the function.
+ * The result value in iv may be used as initialization vector for a chained
+ * call to ica_3des_cmac_initermediate or to ica_3des_cmac_last with the same key.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_3des_cmac_intermediate(const unsigned char *message, unsigned long message_length,
+					const unsigned char *key,
+					unsigned char *iv);
+
+/**
+ * Authenticate data or verify the authenticity of data with an 3DES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B.
+ * ica_3des_cmac_last can be used to authenticate or verify the authenticity
+ * of a complete message or of the final part of a message for which all
+ * preceding parts were preprocessed with ica_3des_cmac_intermediate.
+ *
+ * Required HW Support
+ * KMAC-TDEA-192,
+ * PCC-Compute-Last_block-CMAC-Using-TDEA-192
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a message or the final part of a message to be
+ * authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message to be authenticated or verified.
+ * @param mac
+ * Pointer to a buffer of size greater than or equal to mac_length bytes.
+ * If direction is 1 the buffer must be writable and a message authentication
+ * code for the message in message of size mac_length bytes will be written to
+ * the buffer.
+ * If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the message in message.
+ * @param mac_length
+ * Length in bytes of the message authentication code mac in bytes that is
+ * less than or equal to the cipher block size (I.e. 8 bytes for DES). It is
+ * recommended to use values greater than or equal to 8.
+ * @param key
+ * Pointer to a valid  3DES key of 24 bytes length.
+ * @param iv
+ * Pointer to a valid initialization vector of size cipher block size. If iv
+ * is NULL message is assumed to be the complete message to be processed.
+ * Otherwise message is the final part of a composite message to be processed
+ * and iv contains the output vector resulting from processing all previous
+ * parts with chained calls to ica_3des_cmac_intermediate, i.e. the value
+ * returned in iv of the ica_3des_cmac_intermediate call applied to the
+ * penultimate message part.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code
+ * 1 Compute message authentication code for the message
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_3des_cmac_last(const unsigned char *message, unsigned long message_length,
+				unsigned char *mac, unsigned int mac_length,
+				const unsigned char *key, unsigned char *iv,
+				unsigned int direction);
+
+/**
  * Encrypt or decrypt data with an AES key using Electronic Cook Book (ECB)
  * mode as described in NIST Special Publication 800-38A Chapter 6.1.
  *
@@ -2228,6 +2654,73 @@ unsigned int ica_aes_cbc(const unsigned
 			 unsigned int direction);
 
 /**
+ * Encrypt or decrypt data with an AES key using Cipher Block Chaining with
+ * Ciphertext Stealing (CBC-CS) mode as described in NIST Special Publication
+ * 800-38A Chapter 6.2 and the Addendum to NIST Special Publication 800-38A on
+ * "Recommendation for Block Cipher Modes of Operation: Three Variants of
+ * Ciphertext Stealing for CBC Mode":
+ * ica_aes_cbc_cs may be used to encrypt or decrypt the last chunk of a
+ * message consisting of multiple chunks where all but the last chunk are
+ * encrypted or decrypted by chained calls to ica_aes_cbc and the resulting
+ * iv of the last call to ica_aes_cbc is fed into the iv of the
+ * ica_aes_cbc_cs call provided the chunk is greater than cipher block size
+ * (greater than 16 bytes for AES).
+ *
+ * Required HW Support
+ * KMC-AES-128, KMC-AES-192 or KMC-AES-256
+ *
+ * @param in_data
+ * Pointer to a readable buffer, that contains the message to be en/decrypted.
+ * The size of the message in bytes is data_length. The size of this buffer
+ * in bytes must be at least as big as data_length.
+ * @param out_data
+ * Pointer to a writable buffer, that will contain the resulting en/decrypted
+ * message. The size of this buffer in bytes must be at least as big as
+ * data_length.
+ * @param data_length
+ * Length in bytes of the message to be en/decrypted, which resides at the
+ * beginning of in_data. data_length must be greater than or equal to the
+ * cipher block size (i.e. a multiple of 16 bytes for AES).
+ * @param key
+ * Pointer to a valid AES key.
+ * @param key_length
+ * Length in bytes of the AES key. Supported sizes are 16, 24, and 32 for
+ * AES-128, AES-192 and AES-256 respectively. Therefore, you can use the
+ * macros:
+ * AES_KEY_LEN128, AES_KEY_LEN192, and AES_KEY_LEN256.
+ * @param iv
+ * Pointer to a valid initialization vector of cipher block size bytes. This
+ * vector will be overwritten during the function. For variant equals 1 or
+ * variant equals 2 the result value in iv may be used as initialization vector
+ * for a chained ica_aes_cbc call with the same key if data_length is a
+ * multiple of the cipher block size.
+ * @param direction
+ * 0 or 1:
+ * 0 Use the decrypt function.
+ * 1 Use the encrypt function.
+ * @param variant
+ * 1 Use variant CBC-CS1 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: keep last two blocks in order.
+ * 2 Use variant CBC-CS2 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: switch order of the last two blocks
+ *   if data_length is not a multiple of the cipher block size (i.e. a
+ *   multiple of 8 for DES).
+ * 3 Use variant CBC-CS3 of the Addendum to NIST Special Publication 800-38A
+ *   to encrypt or decrypt the message: always switch order of the last two
+ *   blocks.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_aes_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			    unsigned long data_length,
+			    const unsigned char *key, unsigned int key_length,
+			    unsigned char *iv,
+			    unsigned int direction, unsigned int variant);
+
+/**
  * Encrypt or decrypt data with an AES key using Cipher Feedback (CFB) mode as
  * described in NIST Special Publication 800-38A Chapter 6.3.
  *
@@ -2481,6 +2974,118 @@ unsigned int ica_aes_cmac(const unsigned
 			  unsigned int direction);
 
 /**
+ * Authenticate data or verify the authenticity of data with an AES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as described
+ * in NIST Special Publication 800-38B.
+ * ica_aes_cmc_intermediate and ica_aes_cmac_last can be used when the message
+ * to be authenticated or to be verfied using CMAC is supplied in multiple
+ * chunks. ica_aes_cmac_intermediate is used to process all but the last
+ * chunk. All message chunks to preprocessed by ica_aes_cmac_intermediate
+ * must have a size that is a multiple of the cipher block size (i.e. a
+ * multiple of 16 bytes for AES).
+ * Note: ica_aes_cmac_intermediate has no direction argument it can be used
+ * during an authentication and during authenticity verification.
+ *
+ * Required HW Support
+ * KMAC-AES-128, KMAC-AES-192 or KMAC-AES-256
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a non final part of a message which shall be
+ * authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message part in message. It must be a multiple of
+ * the cipher block size.
+ * @param key
+ * Pointer to a valid AES key.
+ * @param key_length
+ * Length in bytes of the AES key. Supported sizes are 16, 24, and 32 for
+ * AES-128, AES-192 and AES-256 respectively. Therefore, you can use the
+ * macros: AES_KEY_LEN128, AES_KEY_LEN192, and AES_KEY_LEN256.
+ * @param iv
+ * Pointer to a valid  initialization vector of size cipher block size (i.e.
+ * 16 bytes for AES). For the first message part it must be set to a string
+ * of zeros. For processing the n-th message part it must be the resulting iv
+ * value of the ica_aes_cmac_intermediate applied to the (n-1)-th message
+ * part. This vector will be overwritten during the function.
+ * The result value in iv may be used as initialization vector for a chained
+ * call to ica_aes_cmac_initermediate or to ica_aes_cmac_last with the
+ * same key.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ */
+unsigned int ica_aes_cmac_intermediate(const unsigned char *message,
+				       unsigned long message_length,
+				       const unsigned char *key, unsigned int key_length,
+				       unsigned char *iv);
+
+/**
+ * Authenticate data or verify the authenticity of data with an AES key using
+ * the Block Cipher Based Message Authentication Code (CMAC) mode as
+ * described in NIST Special Publication 800-38B.
+ * ica_aes_cmac_last can be used to authenticate or verify the authenticity of
+ * a complete message or of the final part of a message for which all
+ * preceding parts were preprocessed with ica_aes_cmac_intermediate.
+ *
+ * Required HW Support
+ * KMAC-AES-128, KMAC-AES-192 or KMAC-AES-256
+ * PCC-Compute-Last_block-CMAC-Using-AES-128,
+ * PCC-Compute-Last_block-CMAC-Using-AES-192 or
+ * PCC-Compute-Last_block-CMAC-Using-AES-256.
+ *
+ * @param message
+ * Pointer to a readable buffer of size greater than or equal to message_length
+ * bytes. It contains a message or the final part of a message to be
+ * authenticated or of which the authenticity shall be verified.
+ * @param message_length
+ * Length in bytes of the message to be authenticated or verified.
+ * @param mac
+ * Pointer to a buffer of size greater than or equal to mac_length bytes.
+ * If direction is 1 the buffer must be writable and a message authentication
+ * code for the message in message of size mac_length bytes will be written to
+ * the buffer.
+ * If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the message in message.
+ * @param mac_length
+ * Length in bytes of the message authentication code mac in bytes that is less
+ * than or equal to the cipher block size (I.e. 16 bytes for AES). It is
+ * recommended to use values greater than or equal to 8.
+ * @param key
+ * Pointer to a valid AES key.
+ * @param key_length
+ * Length in bytes of the AES key. Supported sizes are 16, 24, and 32 for
+ * AES-128, AES-192 and AES-256 respectively. Therefore, you can use the
+ * macros: AES_KEY_LEN128, AES_KEY_LEN192, and AES_KEY_LEN256.
+ * @param iv
+ * Pointer to a valid initialization vector of size cipher block size. If iv
+ * is NULL message is assumed to be the complete message to be processed.
+ * Otherwise message is the final part of a composite message to be processed
+ * and iv contains the output vector resulting from processing all previous
+ * parts with chained calls to ica_aes_cmac_intermediate, i.e. the value
+ * returned in iv of the ica_aes_cmac_intermediate call applied to the
+ * penultimate message part.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code
+ * 1 Compute message authentication code for the message
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_aes_cmac_last(const unsigned char *message, unsigned long message_length,
+			       unsigned char *mac, unsigned int mac_length,
+			       const unsigned char *key, unsigned int key_length,
+			       unsigned char *iv,
+			       unsigned int direction);
+
+/**
  * Encrypt or decrypt data with an AES key using the XEX Tweakable Bloc Cipher
  * with Ciphertext Stealing (XTS) mode as described in NIST Special Publication
  * 800-38E and IEEE standard 1619-2007.
@@ -2533,6 +3138,163 @@ unsigned int ica_aes_xts(const unsigned
 			 unsigned int direction);
 
 /**
+ * Encrypt and authenticate or decrypt data and check authenticity of data with
+ * an AES key using Counter with Cipher Block Chaining Message Authentication
+ * Code (CCM) mode as described in NIST Special Publication 800-38C.
+ * Formatting and counter functions are implemented according to
+ * NIST 800-38C Appendix A.
+ *
+ * Required HW Support
+ * KMCTR-AES-128, KMCTR-AES-192 or KMCTR-AES-256
+ * KMAC-AES-128, KMAC-AES-192 or KMAC-AES-256
+ *
+ * @param payload
+ * Pointer to a buffer of size greater than or equal to payload_length bytes.
+ * If direction equals 1 the payload buffer must be readable and contain a
+ * payload message of size payload_length that will be encrypted.
+ * If direction equals 0 the payload buffer must be writable. If the
+ * authentication verification succeeds the decrypted message in the most
+ * significant payload_length bytes of ciphertext_n_mac will be written to
+ * the buffer otherwise the contents of the buffer will be undefined.
+ * @param payload_length
+ * Length in bytes of the message to be en/decrypted, it may be 0 unless
+ * assoc_data_length is 0.
+ * @param ciphertext_n_mac
+ * Pointer to a buffer of size greater than or equal to payload_length plus
+ * mac_length bytes.
+ * If direction equals 1 then the buffer must be writable and the encrypted
+ * message from payload followed by the message authentication code for the
+ * nonce, the payload and associated data will be written to that buffer.
+ * If direction equals 0 then the buffer is readable and contains an encrypted
+ * message of length payload_length followed by a message authentication code
+ * of length mac_length.
+ * @param mac_length
+ * Length in bytes of the message authentication code in bytes.
+ * Valid values are 4, 6, 8, 10, 12, 16.
+ * @param assoc_data
+ * Pointer to a readable buffer of size greater than or equal to
+ * assoc_data_length bytes. The associated data in the most significant
+ * assoc_data_lenght bytes is subject to the authentication code computation
+ * but will not be encrypted.
+ * @param assoc_data_length
+ * Length of the associated data in assoc_data. It may be 0 unless
+ * payload_length is 0.
+ * @param nonce
+ * Pointer to readable buffer of size greater than or equal to nonce_length
+ * bytes that contains a nonce of size nonce_length bytes.
+ * @param nonce_length
+ * Length of the nonce in nonce in bytes. Valid values a greater than 6 and
+ * less than 14.
+ * @param key
+ * Pointer to a valid  AES key.
+ * @param key_length
+ * Length in bytes of the AES key. Supported sizes are 16, 24, and 32 for
+ * AES-128, AES-192 and AES-256 respectively. Therefore, you can use the
+ * macros: AES_KEY_LEN128, AES_KEY_LEN192, and AES_KEY_LEN256.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code and decrypt encrypted payload.
+ * 1 Encrypt payload and compute message authentication code for the nonce,
+ * the associated data and the payload.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_aes_ccm(unsigned char *payload, unsigned long payload_length,
+			 unsigned char *ciphertext_n_mac, unsigned int mac_length,
+			 const unsigned char *assoc_data, unsigned long assoc_data_length,
+			 const unsigned char *nonce, unsigned int nonce_length,
+			 const unsigned char *key, unsigned int key_length,
+			 unsigned int direction);
+
+/**
+ * Encrypt and authenticate or decrypt data and check authenticity data with
+ * an AES key using the Galois/Counter (GCM) mode as described in NIST Special
+ * Publication 800-38D.
+ * If no message needs to be encrypted or decrypted and only authentication or
+ * authentication checks are requested then this method implements the GMAC
+ * mode.
+ *
+ * Required HW Support
+ * KM-AES-128, KM-AES-192 or KM-AES-256
+ * KIMD-GHASH
+ * KMCTR-AES-128, KMCTR_AES-192 or KMCTR-AES-256
+ *
+ * @param plaintext
+ * Pointer to a buffer of size greater than or equal to plaintext_length bytes.
+ * If direction equals 1 the plaintext buffer must be readable and contain a
+ * payload message of size plaintext_length that will be encrypted.
+ * If direction equals 0 the plaintext buffer must be writable. If the
+ * authentication verification succeeds  the decrypted message in the most
+ * significant plaintext_length bytes of ciphertext will be written to the
+ * buffer otherwise the contents of the buffer will be undefined.
+ * @param plaintext_length
+ * Length in bytes of the message to be en/decrypted. It must be equal or
+ * greater than 0 and less than (2^36)-32.
+ * @param ciphertext
+ * Pointer to a buffer of size greater than or equal to plaintext_length
+ * bytes.
+ * If direction equals 1 then the buffer must be writable and the encrypted
+ * message from plaintext will be written to that buffer.
+ * If direction equals 0 then the buffer is readable and contains an encrypted
+ * message of length plaintext_length.
+ * @param iv
+ * Pointer to a readable buffer of size greater than or equal to iv_length
+ * bytes, that contains an initialization vector of size iv_length.
+ * @param iv_length
+ * Length in bytes of the initialization vector in iv. It must be greater
+ * than 0 and less than 2^61. A length of 12 is recommended.
+ * @param aad
+ * Pointer to a readable buffer of size greater than or equal to aad_length
+ * bytes. The additional authenticated data in the most significant aad_length
+ * bytes is subject to the authentication code computation but will not be
+ * encrypted.
+ * @param aad_length
+ * Length in bytes of the additional authenticated data in aad. It must be
+ * equal or greater than 0 and less than 2^61.
+ * @param tag
+ * Pointer to a buffer of size greater than or equal to tag_length bytes.
+ * If direction is 1 the buffer must be writable and a message authentication
+ * code for the additional authenticated data in aad and the plain text in
+ * plaintext of size tag_length bytes will be written to the buffer.
+ * If direction is 0 the buffer must be readable and contain a message
+ * authentication code that will be verified against the additional
+ * authenticated data in aad and decrypted cipher text from ciphertext.
+ * @param tag_length
+ * Length in bytes of the message authentication code tag in bytes.
+ * Valid values are 4, 8, 12, 13, 14, 15, 16.
+ * @param key
+ * Pointer to a valid AES key.
+ * @param key_length
+ * Length in bytes of the AES key. Supported sizes are 16, 24, and 32 for
+ * AES-128, AES-192 and AES-256 respectively. Therefore, you can use the
+ * macros: AES_KEY_LEN128, AES_KEY_LEN192, and AES_KEY_LEN256.
+ * @param direction
+ * 0 or 1:
+ * 0 Verify message authentication code and decrypt encrypted payload.
+ * 1 Encrypt payload and compute message authentication code for the additional
+ * authenticated data and the payload.
+ *
+ * @return 0 on success
+ * EINVAL if at least one invalid parameter is given.
+ * EPERM if required hardware support is not available.
+ * EIO if the operation fails.
+ * EFAULT if direction is 0 and the verification of the message authentication
+ * code fails.
+ */
+unsigned int ica_aes_gcm(unsigned char *plaintext, unsigned long plaintext_length,
+			 unsigned char *ciphertext,
+			 const unsigned char *iv, unsigned int iv_length,
+			 const unsigned char *aad, unsigned long aad_length,
+			 unsigned char *tag, unsigned int tag_length,
+			 const unsigned char *key, unsigned int key_length,
+			 unsigned int direction);
+
+/**
  * Return libica version information.
  * @param version_info
  * Pointer to a libica_version_info structure. The structure will be
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,9 +5,9 @@ lib_LTLIBRARIES = libica.la
 libica_la_LDFLAGS = -release $(PACKAGE_VERSION) -lrt -lcrypto
 
 libica_la_SOURCES = icalinux.c ica_api.c init.c icastats_shared.c \
-		    s390_rsa.c s390_crypto.c s390_des.c \
+		    s390_rsa.c s390_crypto.c s390_common.c s390_des.c \
 		    s390_aes.c s390_prng.c s390_sha.c opencryptoki_api.c \
-		    s390_cmac.c s390_ctr.c
+		    s390_cmac.c s390_ctr.c s390_cbccs.c s390_ccm.c s390_gcm.c
 
 bin_PROGRAMS = icainfo icastats
 
--- a/src/ica_api.c
+++ b/src/ica_api.c
@@ -31,6 +31,9 @@
 #include "s390_des.h"
 #include "s390_aes.h"
 #include "s390_cmac.h"
+#include "s390_cbccs.h"
+#include "s390_ccm.h"
+#include "s390_gcm.h"
 
 #define DEFAULT_CRYPT_DEVICE "/udev/z90crypt"
 #define DEFAULT2_CRYPT_DEVICE "/dev/z90crypt"
@@ -61,6 +64,11 @@ static unsigned int check_des_parms(unsi
 		if (data_length & 0x07)
 			return EINVAL;
 		break;
+	case MODE_CBCCS:
+		if (iv == NULL)
+			return EINVAL;
+		if (data_length <= DES_BLOCK_SIZE)
+			return EINVAL;
 	case MODE_CFB:
 		if (iv == NULL)
 			return EINVAL;
@@ -110,6 +118,11 @@ static unsigned int check_aes_parms(unsi
 		if (data_length & 0x0F)
 			return EINVAL;
 		break;
+	case MODE_CBCCS:
+		if (iv == NULL)
+			return EINVAL;
+		if (data_length <= AES_BLOCK_SIZE)
+			return EINVAL;
 	case MODE_CFB:
 		if (iv == NULL)
 			return EINVAL;
@@ -130,6 +143,11 @@ static unsigned int check_aes_parms(unsi
 		if (data_length < AES_BLOCK_SIZE)
 			return EINVAL;
 		break;
+	case MODE_CCM:
+	case MODE_GCM:
+		if (iv == NULL)
+			return EINVAL;
+		break;
 	default:
 		/* unsupported mode */
 		return EINVAL;
@@ -138,17 +156,108 @@ static unsigned int check_aes_parms(unsi
 	return 0;
 }
 
-static unsigned int check_cmac_parms(unsigned int key_length,
-				     unsigned int cbc_mac_length)
+static unsigned int check_cmac_parms(unsigned int block_size,
+				     const unsigned char *message, unsigned int message_length,
+				     unsigned char *mac, unsigned int mac_length,
+				     const unsigned char *keys, unsigned int key_length,
+				     unsigned char *iv)
 {
-	/* check for obvious errors in parms */
-	if ((( key_length != AES_KEY_LEN128 ) &&
-	     ( key_length != AES_KEY_LEN192 ) &&
-	     ( key_length != AES_KEY_LEN256 )) ||
-	    ( cbc_mac_length == 0 ) ||
-	    ( cbc_mac_length > AES_BLOCK_SIZE )
-	   )
+
+	if (keys == NULL)
+		return EINVAL;
+
+	if (mac == NULL) {		/* intermediate */
+		if (iv == NULL)
+			return EINVAL;
+
+		if (message_length % block_size)
+			return EINVAL;
+	}
+
+	if ((mac_length == 0) ||
+	    (mac_length > block_size))
+		return EINVAL;
+
+	if ((message_length != 0) &&
+	    (message == NULL))
+		return EINVAL;
+
+	switch (block_size) {
+	case DES_BLOCK_SIZE:
+		break;
+	case AES_BLOCK_SIZE:
+		if ((key_length != AES_KEY_LEN128) &&
+		    (key_length != AES_KEY_LEN192) &&
+		    (key_length != AES_KEY_LEN256))
+			return EINVAL;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int check_gcm_parms(unsigned long text_length,
+				    const unsigned char *aad,
+				    unsigned long aad_length,
+				    const unsigned char *tag, unsigned int tag_length,
+				    unsigned int iv_length)
+{
+	if ((text_length > S390_GCM_MAX_TEXT_LENGTH) ||
+	    (aad_length  > S390_GCM_MAX_AAD_LENGTH) ||
+	    (iv_length   > S390_GCM_MAX_IV_LENGTH) ||
+	    (iv_length == 0))
+		return EINVAL;
+
+	if (tag == NULL)
+		return EINVAL;
+
+	switch (tag_length) {
+	case 4:
+	case 8:
+	case 12:
+	case 13:
+	case 14:
+	case 15:
+	case 16:
+		break;
+	default:
+		return EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int check_ccm_parms(unsigned long payload_length,
+				    const unsigned char *assoc_data,
+				    unsigned long assoc_data_length,
+				    const unsigned char *mac,
+				    unsigned int mac_length,
+				    unsigned int nonce_length)
+{
+	if ((payload_length == 0) && (assoc_data_length == 0))
+		return EINVAL;
+
+	if ((nonce_length > S390_CCM_MAX_NONCE_LENGTH) ||
+	    (nonce_length < S390_CCM_MIN_NONCE_LENGTH))
+		return EINVAL;
+
+	/* if nonce_length is equal S390_CCM_MIN_NONCE_LENGTH, payload_length
+	 * is only limited by the value range of its data type unsigned long
+	 * and need no further checking */
+	if ((nonce_length > S390_CCM_MIN_NONCE_LENGTH) &&
+	    (payload_length > ((1ul << (8*(15-nonce_length))))))
+		return EINVAL;
+
+	if (mac == NULL)
+		return EINVAL;
+
+	if ((mac_length > S390_CCM_MAX_MAC_LENGTH) ||
+	    (mac_length < S390_CCM_MIN_MAC_LENGTH) ||
+	    (mac_length % 2))
 		return EINVAL;
+
 	return 0;
 }
 
@@ -739,6 +848,19 @@ unsigned int ica_des_cbc(const unsigned
 			    in_data, iv, key, out_data);
 }
 
+unsigned int ica_des_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			    unsigned long data_length,
+			    const unsigned char *key, unsigned char *iv,
+			    unsigned int direction, unsigned int variant)
+{
+	if (check_des_parms(MODE_CBCCS, data_length, in_data, iv, key, out_data))
+		return EINVAL;
+
+	return s390_des_cbccs(des_directed_fc(direction),
+			      in_data, out_data, data_length,
+			      key, iv, variant);
+}
+
 unsigned int ica_des_cfb(const unsigned char *in_data, unsigned char *out_data,
 			 unsigned long data_length, const unsigned char *key,
 			 unsigned char *iv, unsigned int lcfb,
@@ -798,6 +920,79 @@ unsigned int ica_des_ctrlist(const unsig
 				key, out_data);
 }
 
+unsigned int ica_des_cmac(const unsigned char *message, unsigned long message_length,
+			  unsigned char *mac, unsigned int mac_length,
+			  const unsigned char *key,
+			  unsigned int direction)
+{
+	return ica_des_cmac_last(message, message_length,
+				 mac, mac_length,
+				 key,
+				 NULL,
+				 direction);
+}
+
+unsigned int ica_des_cmac_intermediate(const unsigned char *message,
+				       unsigned long message_length,
+				       const unsigned char *key,
+				       unsigned char *iv)
+{
+	unsigned long function_code;
+	int rc;
+
+	if (check_cmac_parms(DES_BLOCK_SIZE,
+			     message, message_length,
+			     NULL, DES_BLOCK_SIZE,	/* no mac available (intermediate) */
+			     key, DES_BLOCK_SIZE,
+			     iv))
+		return EINVAL;
+
+	function_code = des_directed_fc(ICA_DECRYPT);
+	rc = s390_cmac(function_code, message, message_length,
+		       DES_BLOCK_SIZE, key,
+		       DES_BLOCK_SIZE, NULL,	/* no mac available (intermediate) */
+		       iv);
+
+	return rc;
+}
+
+unsigned int ica_des_cmac_last(const unsigned char *message, unsigned long message_length,
+			       unsigned char *mac, unsigned int mac_length,
+			       const unsigned char *key,
+			       unsigned char *iv,
+			       unsigned int direction)
+{
+	unsigned char tmp_mac[DES_BLOCK_SIZE];
+	unsigned long function_code;
+	int rc;
+
+	if (check_cmac_parms(DES_BLOCK_SIZE,
+			     message, message_length,
+			     mac, mac_length,
+			     key, DES_BLOCK_SIZE,
+			     iv))
+		return EINVAL;
+
+	function_code = des_directed_fc(direction);
+	if (direction) {
+		/* generate */
+		rc = s390_cmac(function_code, message, message_length,
+			       DES_BLOCK_SIZE, key, mac_length, mac, iv);
+		if (rc)
+			return rc;
+	} else {
+		/* verify */
+		rc = s390_cmac(function_code, message, message_length,
+			       DES_BLOCK_SIZE, key, mac_length, tmp_mac, iv);
+		if (rc)
+			return rc;
+		if (memcmp(tmp_mac, mac, mac_length))
+			return EFAULT;
+	}
+
+	return 0;
+}
+
 unsigned int ica_3des_ecb(const unsigned char *in_data, unsigned char *out_data,
 			  unsigned long data_length, const unsigned char *key,
 			  unsigned int direction)
@@ -821,6 +1016,19 @@ unsigned int ica_3des_cbc(const unsigned
 			    in_data, iv, key, out_data);
 }
 
+unsigned int ica_3des_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			     unsigned long data_length,
+			     const unsigned char *key, unsigned char *iv,
+			     unsigned int direction, unsigned int variant)
+{
+	if (check_des_parms(MODE_CBCCS, data_length, in_data, iv, key, out_data))
+		return EINVAL;
+
+	return s390_des_cbccs(tdes_directed_fc(direction),
+			      in_data, out_data, data_length,
+			      key, iv, variant);
+}
+
 unsigned int ica_3des_cfb(const unsigned char *in_data, unsigned char *out_data,
 			  unsigned long data_length, const unsigned char *key,
 			  unsigned char *iv, unsigned int lcfb,
@@ -880,6 +1088,79 @@ unsigned int ica_3des_ctrlist(const unsi
 				key, out_data);
 }
 
+unsigned int ica_3des_cmac(const unsigned char *message, unsigned long message_length,
+			   unsigned char *mac, unsigned int mac_length,
+			   const unsigned char *key,
+			   unsigned int direction)
+{
+	return ica_3des_cmac_last(message, message_length,
+				  mac, mac_length,
+				  key,
+				  NULL,
+				  direction);
+}
+
+unsigned int ica_3des_cmac_intermediate(const unsigned char *message,
+					unsigned long message_length,
+					const unsigned char *key,
+					unsigned char *iv)
+{
+	unsigned long function_code;
+	int rc;
+
+	if (check_cmac_parms(DES_BLOCK_SIZE,
+			     message, message_length,
+			     NULL, DES_BLOCK_SIZE,	/* no mac available (intermediate) */
+			     key, 3*DES_BLOCK_SIZE,
+			     iv))
+		return EINVAL;
+
+	function_code = tdes_directed_fc(ICA_DECRYPT);
+	rc = s390_cmac(function_code, message, message_length,
+		       3*DES_BLOCK_SIZE, key,
+		       DES_BLOCK_SIZE, NULL,	/* no mac available (intermediate) */
+		       iv);
+
+	return rc;
+}
+
+unsigned int ica_3des_cmac_last(const unsigned char *message, unsigned long message_length,
+				unsigned char *mac, unsigned int mac_length,
+				const unsigned char *key,
+				unsigned char *iv,
+				unsigned int direction)
+{
+	unsigned char tmp_mac[DES_BLOCK_SIZE];
+	unsigned long function_code;
+	int rc;
+
+	if (check_cmac_parms(DES_BLOCK_SIZE,
+			     message, message_length,
+			     mac, mac_length,
+			     key, 3*DES_BLOCK_SIZE,
+			     iv))
+		return EINVAL;
+
+	function_code = tdes_directed_fc(direction);
+	if (direction) {
+		/* generate */
+		rc = s390_cmac(function_code, message, message_length,
+			       3*DES_BLOCK_SIZE, key, mac_length, mac, iv);
+		if (rc)
+			return rc;
+	} else {
+		/* verify */
+		rc = s390_cmac(function_code, message, message_length,
+			       3*DES_BLOCK_SIZE, key, mac_length, tmp_mac, iv);
+		if (rc)
+			return rc;
+		if (memcmp(tmp_mac, mac, mac_length))
+			return EFAULT;
+	}
+
+	return 0;
+}
+
 unsigned int ica_aes_ecb(const unsigned char *in_data, unsigned char *out_data,
 			 unsigned long data_length, const unsigned char *key,
 			 unsigned int key_length,
@@ -908,6 +1189,22 @@ unsigned int ica_aes_cbc(const unsigned
 	return s390_aes_cbc(function_code, data_length, in_data, iv, key, out_data);
 }
 
+unsigned int ica_aes_cbc_cs(const unsigned char *in_data, unsigned char *out_data,
+			    unsigned long data_length,
+			    const unsigned char *key, unsigned int key_length,
+			    unsigned char *iv,
+			    unsigned int direction, unsigned int variant)
+{
+	unsigned int function_code;
+	if (check_aes_parms(MODE_CBCCS, data_length, in_data, iv, key_length,
+			    key, out_data))
+		return EINVAL;
+
+	function_code = aes_directed_fc(key_length, direction);
+	return s390_aes_cbccs(function_code, in_data, out_data, data_length,
+			      key, key_length, iv, variant);
+}
+
 unsigned int ica_aes_cfb(const unsigned char *in_data, unsigned char *out_data,
 			 unsigned long data_length, const unsigned char *key,
 			 unsigned int key_length, unsigned char *iv, unsigned int lcfb,
@@ -1017,30 +1314,166 @@ unsigned int ica_aes_cmac(const unsigned
 			  const unsigned char *key, unsigned int key_length,
 			  unsigned int direction)
 {
+	return ica_aes_cmac_last(message, message_length,
+				 mac, mac_length,
+				 key, key_length,
+				 NULL,
+				 direction);
+}
+
+unsigned int ica_aes_cmac_intermediate(const unsigned char *message,
+				       unsigned long message_length,
+				       const unsigned char *key, unsigned int key_length,
+				       unsigned char *iv)
+{
+	unsigned long function_code;
+	int rc;
+
+	if (check_cmac_parms(AES_BLOCK_SIZE,
+			     message, message_length,
+			     NULL, AES_BLOCK_SIZE,	/* no mac available (intermediate) */
+			     key, key_length,
+			     iv))
+		return EINVAL;
+
+	function_code = aes_directed_fc(key_length, ICA_DECRYPT);
+	rc = s390_cmac(function_code, message, message_length,
+		       key_length, key,
+		       AES_BLOCK_SIZE, NULL,	/* no mac available (intermediate) */
+		       iv);
+
+	return rc;
+}
+
+unsigned int ica_aes_cmac_last(const unsigned char *message, unsigned long message_length,
+			       unsigned char *mac, unsigned int mac_length,
+			       const unsigned char *key, unsigned int key_length,
+			       unsigned char *iv,
+			       unsigned int direction)
+{
 	unsigned char tmp_mac[AES_BLOCK_SIZE];
 	unsigned long function_code;
 	int rc;
 
-	if (check_cmac_parms(key_length, mac_length))
+	if (check_cmac_parms(AES_BLOCK_SIZE,
+			     message, message_length,
+			     mac, mac_length,
+			     key, key_length,
+			     iv))
 		return EINVAL;
 
 	function_code = aes_directed_fc(key_length, direction);
 	if (direction) {
 		/* generate */
 		rc = s390_cmac(function_code, message, message_length,
-			       key_length, key, mac_length, mac);
+			       key_length, key, mac_length, mac, iv);
 		if (rc)
 			return rc;
 	} else {
 		/* verify */
 		rc = s390_cmac(function_code, message, message_length,
-			       key_length, key, mac_length, tmp_mac);
+			       key_length, key, mac_length, tmp_mac, iv);
 		if (rc)
 			return rc;
 		if (memcmp(tmp_mac, mac, mac_length))
 			return EFAULT;
 	}
 
+	return 0;
+}
+
+unsigned int ica_aes_ccm(unsigned char *payload, unsigned long payload_length,
+			 unsigned char *ciphertext_n_mac, unsigned int mac_length,
+			 const unsigned char *assoc_data, unsigned long assoc_data_length,
+			 const unsigned char *nonce, unsigned int nonce_length,
+			 const unsigned char *key, unsigned int key_length,
+			 unsigned int direction)
+{
+	unsigned char tmp_mac[AES_BLOCK_SIZE];
+	unsigned char *mac;
+	unsigned long function_code;
+	int rc;
+
+	if (check_aes_parms(MODE_CCM, payload_length, payload, nonce, key_length,
+			    key, ciphertext_n_mac))
+		return EINVAL;
+	if (check_ccm_parms(payload_length,
+			    assoc_data, assoc_data_length,
+			    ciphertext_n_mac + payload_length, mac_length,
+			    nonce_length))
+		return EINVAL;
+
+	function_code = aes_directed_fc(key_length, direction);
+	mac = (direction == ICA_ENCRYPT) ?
+		(unsigned char *)(ciphertext_n_mac + payload_length) :
+		tmp_mac;
+
+	rc = s390_ccm(function_code,
+		      payload, payload_length,
+		      ciphertext_n_mac,
+		      assoc_data, assoc_data_length,
+		      nonce, nonce_length,
+		      mac, mac_length,
+		      key);
+	if (rc)
+		return rc;
+
+	if (direction == ICA_DECRYPT) {
+		/* verify */
+		if (memcmp((unsigned char *)(ciphertext_n_mac + payload_length),
+			   tmp_mac, mac_length))
+			return EFAULT;
+	}
+
+	return 0;
+}
+
+unsigned int ica_aes_gcm(unsigned char *plaintext, unsigned long plaintext_length,
+			 unsigned char *ciphertext,
+			 const unsigned char *iv, unsigned int iv_length,
+			 const unsigned char *aad, unsigned long aad_length,
+			 unsigned char *tag, unsigned int tag_length,
+			 const unsigned char *key, unsigned int key_length,
+			 unsigned int direction)
+{
+	unsigned char tmp_tag[AES_BLOCK_SIZE];
+	unsigned long function_code;
+	int rc;
+
+	if (check_aes_parms(MODE_GCM, plaintext_length, plaintext, iv, key_length,
+			    key, ciphertext))
+		return EINVAL;
+	if (check_gcm_parms(plaintext_length, aad, aad_length, tag, tag_length, iv_length))
+		return EINVAL;
+
+	function_code = aes_directed_fc(key_length, direction);
+	if (direction) {
+		/* encrypt & generate */
+		rc = s390_gcm(function_code,
+			      plaintext, plaintext_length,
+			      ciphertext,
+			      iv, iv_length,
+			      aad, aad_length,
+			      tag, tag_length,
+			      key);
+		if (rc)
+			return rc;
+	} else {
+		/* decrypt & verify */
+		rc = s390_gcm(function_code,
+			      plaintext, plaintext_length,
+			      ciphertext,
+			      iv, iv_length,
+			      aad, aad_length,
+			      tmp_tag, AES_BLOCK_SIZE,
+			      key);
+		if (rc)
+			return rc;
+
+		if (memcmp(tmp_tag, tag, tag_length))
+			return EFAULT;
+	}
+
 	return 0;
 }
 
--- a/src/icastats.c
+++ b/src/icastats.c
@@ -67,6 +67,12 @@ const char *const STATS_DESC[ICA_NUM_STA
 	"AES DEC",
 	"CMAC GEN",
 	"CMAC VER",
+	"CCM ENC",
+	"CCM DEC",
+	"CCM AUTH",
+	"GCM ENC",
+	"GCM DEC",
+	"GCM AUTH",
 };
 
 int main(int argc, char *argv[])
--- a/src/include/icastats.h
+++ b/src/include/icastats.h
@@ -32,6 +32,12 @@ typedef enum stats_fields {
 	ICA_STATS_AES_DECRYPT,
 	ICA_STATS_CMAC_GENERATE,
 	ICA_STATS_CMAC_VERIFY,
+	ICA_STATS_CCM_ENCRYPT,
+	ICA_STATS_CCM_DECRYPT,
+	ICA_STATS_CCM_AUTH,
+	ICA_STATS_GCM_ENCRYPT,
+	ICA_STATS_GCM_DECRYPT,
+	ICA_STATS_GCM_AUTH,
 
 	ICA_NUM_STATS
 } stats_fields_t;
--- /dev/null
+++ b/src/include/s390_cbccs.h
@@ -0,0 +1,24 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2011
+ */
+
+#ifndef S390_CBCCS_H
+#define S390_CBCCS_H
+
+int s390_des_cbccs(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key,
+		   unsigned char *iv, unsigned int variant);
+int s390_aes_cbccs(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key, unsigned int key_length,
+		   unsigned char *iv, unsigned int variant);
+#endif
--- /dev/null
+++ b/src/include/s390_ccm.h
@@ -0,0 +1,38 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Ruben Straus <rstraus@de.ibm.com>
+ * 	    Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2010
+ */
+
+#ifndef S390_CCM
+#define S390_CCM_H
+
+#define S390_CCM_MAX_NONCE_LENGTH 13
+#define S390_CCM_MIN_NONCE_LENGTH  7
+#define S390_CCM_MAX_MAC_LENGTH   16
+#define S390_CCM_MIN_MAC_LENGTH    4
+
+unsigned int s390_ccm(unsigned int function_code,
+		      unsigned char *payload, unsigned long payload_length,
+		      unsigned char *ciphertext,
+		      const unsigned char *assoc_data, unsigned long assoc_data_length,
+		      const unsigned char *nonce, unsigned long nonce_length,
+		      unsigned char *mac, unsigned long mac_length,
+		      const unsigned char *key);
+/*
+int s390_ccm(unsigned long fc, unsigned long payload_length,
+	unsigned char *payload, unsigned long assoc_data_length,
+	unsigned char *assoc_data, unsigned int nonce_length,
+	unsigned char *nonce, unsigned int cbc_mac_length,
+	unsigned int key_length, unsigned char *key,
+	unsigned long cipther_text_length, unsigned char *cipher_text);
+*/
+#endif
+
--- a/src/include/s390_cmac.h
+++ b/src/include/s390_cmac.h
@@ -17,7 +17,8 @@
 int s390_cmac(unsigned long fc,
 	      const unsigned char *message, unsigned long message_length,
 	      unsigned int key_length, const unsigned char *key,
-	      unsigned int cmac_length, unsigned char *cmac);
+	      unsigned int cmac_length, unsigned char *cmac,
+	      unsigned char *iv);
 
 #endif
 
--- /dev/null
+++ b/src/include/s390_common.h
@@ -0,0 +1,33 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2011
+ */
+
+#ifndef S390_COMMON_H
+#define S390_COMMON_H
+
+#define UNDIRECTED_FC(x) (((x)/2)*2)
+
+void ctr_inc_block(unsigned char *iv, unsigned int block_size,
+		   unsigned int ctr_width, unsigned char *ctrlist,
+		   unsigned long ctrlist_length);
+
+void ctr_inc_single(unsigned char *iv, unsigned int block_size,
+		    unsigned int ctr_width);
+
+inline void memcpy_r_allign(void *dest, int dest_bs,
+		     void *src, int src_bs, int size);
+
+inline void block_xor(unsigned char dest[],
+		      unsigned char a[], unsigned char b[],
+		      unsigned int length);
+
+#endif /* S390_COMMON_H */
+
--- /dev/null
+++ b/src/include/s390_gcm.h
@@ -0,0 +1,30 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Felix Beck <felix.beck@de.ibm.com>
+ * 	    Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2010, 2011
+ */
+
+#ifndef S390_GCM_H
+#define S390_GCM_H
+
+#define S390_GCM_MAX_TEXT_LENGTH (0x0000000fffffffe0ul) /* (2^31)-32 */
+#define S390_GCM_MAX_AAD_LENGTH  (0x2000000000000000ul) /* (2^61)    */
+#define S390_GCM_MAX_IV_LENGTH   (0x2000000000000000ul) /* (2^61)    */
+
+int s390_gcm(unsigned int function_code,
+	     unsigned char *plaintext, unsigned long text_length,
+	     unsigned char *ciphertext,
+	     const unsigned char *iv, unsigned long iv_length,
+	     const unsigned char *aad, unsigned long aad_length,
+	     unsigned char *tag, unsigned long tag_length,
+	     const unsigned char *key);
+inline int s390_ghash(const unsigned char *in_data, unsigned long data_length,
+		      const unsigned char *key, unsigned char *iv);
+#endif
--- /dev/null
+++ b/src/s390_cbccs.c
@@ -0,0 +1,323 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2011
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include <ica_api.h>
+
+#include "icastats.h"
+#include "s390_crypto.h"
+#include "s390_des.h"
+#include "s390_aes.h"
+#include "s390_common.h"
+
+static inline unsigned int
+cbccs_last_block_swap(unsigned char *base, unsigned long length,
+		      unsigned int block_size,
+		      unsigned int direction, unsigned int variant)
+{
+	unsigned char tmp[block_size];
+	unsigned long rest_length;
+	unsigned long head_length;
+
+	rest_length = length % block_size;
+
+	switch (variant) {
+	case 1:
+		/* keep last two blocks in order */
+		break;
+	case 2:
+		/* switch order of the last two blocks if length is not
+		 * a multiple of the cipher block size, otherwise keep last
+		 * two blocks in order */
+		if (rest_length == 0)
+			break;
+	case 3:
+		/* always switch order of the last two blocks */
+		if (rest_length == 0)
+			rest_length = block_size;
+		head_length = length - rest_length;
+
+		if (direction) {
+			/* encrypt */
+			memcpy(tmp,
+			       base + (head_length - block_size) + rest_length,
+			       block_size);
+			memcpy(base + head_length,
+			       base + (head_length - block_size),
+			       rest_length);
+			memcpy(base + (head_length - block_size),
+			       tmp,
+			       block_size);
+		} else {
+			/*decrypt */
+			memcpy(tmp,
+			       base + (head_length - block_size),
+			       block_size);
+			memcpy(base + (head_length - block_size),
+			       base + head_length,
+			       rest_length);
+			memcpy(base + (head_length - block_size) + rest_length,
+			       tmp,
+			       block_size);
+		}
+		break;
+	default:
+		/* unsupported variant */
+		return EINVAL;
+	}
+
+	return 0;
+}
+static unsigned int
+s390_des_cbccs_enc(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key,
+		   unsigned char *iv, unsigned int variant)
+{
+	unsigned int rc;
+	unsigned char tmp_in_data[DES_BLOCK_SIZE];
+	unsigned long rest_data_length;
+	unsigned long tmp_data_length;
+
+	rest_data_length = data_length % DES_BLOCK_SIZE;
+	tmp_data_length = data_length - rest_data_length;
+
+	/* tmp_data_length is at least DES_BLOCK_SIZE */
+	rc = s390_des_cbc(fc, tmp_data_length, in_data, iv, key, out_data);
+	if (rc)
+		return rc;
+
+	if (rest_data_length) {
+		/* zero padding for uncomplete last block */
+		memset(tmp_in_data, 0, DES_BLOCK_SIZE);
+		memcpy(tmp_in_data, in_data + tmp_data_length, rest_data_length);
+
+		rc = s390_des_cbc(fc, DES_BLOCK_SIZE, tmp_in_data, iv, key,
+				  out_data + (tmp_data_length - DES_BLOCK_SIZE) +
+				  rest_data_length);
+		if (rc)
+			return rc;
+	}
+
+	return cbccs_last_block_swap(out_data, data_length,
+				     DES_BLOCK_SIZE, ICA_ENCRYPT, variant);
+}
+
+static unsigned int
+s390_des_cbccs_dec(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key,
+		   unsigned char *iv, unsigned int variant)
+{
+	unsigned int rc;
+	unsigned char tmp_in_data[2* DES_BLOCK_SIZE];
+	unsigned long rest_data_length;
+	unsigned long swap_length;
+	unsigned long tmp_data_length;
+	unsigned char tmp_iv[DES_BLOCK_SIZE];
+	unsigned char tmp_out_data[DES_BLOCK_SIZE];
+
+	rest_data_length = data_length % DES_BLOCK_SIZE;
+	swap_length = (rest_data_length) ?
+		DES_BLOCK_SIZE + rest_data_length :
+		2* DES_BLOCK_SIZE;
+	tmp_data_length = data_length - swap_length;
+
+	/* copy last 2 blocks to temporary buffer, because blocks can not
+	 * be re-ordered in in_data (const) */
+	memset(tmp_in_data, 0, 2*DES_BLOCK_SIZE);
+	memcpy(tmp_in_data, in_data + tmp_data_length, swap_length);
+
+	rc = cbccs_last_block_swap(tmp_in_data, swap_length,
+				   DES_BLOCK_SIZE, ICA_DECRYPT, variant);
+	if (rc)
+		return rc;
+
+	if (rest_data_length == 0) {
+		/* complete message handling */
+		if (tmp_data_length) {
+			rc = s390_des_cbc(fc, tmp_data_length, in_data,
+					  iv, key, out_data);
+			if (rc)
+				return rc;
+		}
+
+		return s390_des_cbc(fc, swap_length, tmp_in_data,
+				    iv, key, out_data + tmp_data_length);
+	}
+
+	if (tmp_data_length) {
+		rc = s390_des_cbc(fc, tmp_data_length, in_data,
+				  iv, key, out_data);
+		if (rc)
+			return rc;
+	}
+
+	/* decrypt block C(n) with zero iv */
+	memset(tmp_iv, 0, DES_BLOCK_SIZE);
+	rc = s390_des_cbc(fc, DES_BLOCK_SIZE,
+			  tmp_in_data + rest_data_length,
+			  tmp_iv, key, tmp_out_data);
+	if(rc)
+		return rc;
+
+	/* complete block C*(n-1) to C(n-1) and decrypt it */
+	memcpy_r_allign(tmp_in_data, DES_BLOCK_SIZE,
+			tmp_out_data, DES_BLOCK_SIZE,
+			DES_BLOCK_SIZE - rest_data_length);
+	rc = s390_des_cbc(fc, DES_BLOCK_SIZE, tmp_in_data,
+			  iv, key, out_data + tmp_data_length);
+	if(rc)
+		return rc;
+
+	/* XOR tmp_out_data with C*(n-1) */
+	block_xor(out_data + tmp_data_length + DES_BLOCK_SIZE,
+		  tmp_in_data, tmp_out_data, rest_data_length);
+
+	return 0;
+}
+
+static unsigned int
+s390_aes_cbccs_enc(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key, unsigned int key_length,
+		   unsigned char *iv, unsigned int variant)
+{
+	unsigned int rc;
+	unsigned char tmp_in_data[AES_BLOCK_SIZE];
+	unsigned long rest_data_length;
+	unsigned long tmp_data_length;
+
+	rest_data_length = data_length % AES_BLOCK_SIZE;
+	tmp_data_length = data_length - rest_data_length;
+
+	/* tmp_data_length is at least AES_BLOCK_SIZE */
+	rc = s390_aes_cbc(fc, tmp_data_length, in_data, iv, key, out_data);
+	if (rc)
+		return rc;
+
+	if (rest_data_length) {
+		memset(tmp_in_data, 0, AES_BLOCK_SIZE);
+		memcpy(tmp_in_data, in_data + tmp_data_length, AES_BLOCK_SIZE);
+
+		rc = s390_aes_cbc(fc, AES_BLOCK_SIZE, tmp_in_data, iv, key,
+				  out_data + (tmp_data_length - AES_BLOCK_SIZE) +
+				  rest_data_length);
+		if (rc)
+			return rc;
+	}
+
+	return cbccs_last_block_swap(out_data, data_length,
+				     AES_BLOCK_SIZE, ICA_ENCRYPT, variant);
+}
+
+static unsigned int
+s390_aes_cbccs_dec(unsigned int fc, const unsigned char *in_data,
+		   unsigned char *out_data, unsigned long data_length,
+		   const unsigned char *key, unsigned int key_length,
+		   unsigned char *iv, unsigned int variant)
+{
+	unsigned int rc;
+	unsigned char tmp_in_data[2* AES_BLOCK_SIZE];
+	unsigned long rest_data_length;
+	unsigned long swap_length;
+	unsigned long tmp_data_length;
+	unsigned char tmp_iv[AES_BLOCK_SIZE];
+	unsigned char tmp_out_data[AES_BLOCK_SIZE];
+
+	rest_data_length = data_length % AES_BLOCK_SIZE;
+	swap_length = (rest_data_length) ?
+		(AES_BLOCK_SIZE + rest_data_length) :
+		(2* AES_BLOCK_SIZE);
+	tmp_data_length = data_length - swap_length;
+
+	/* copy last 2 blocks to temporary buffer, because blocks can not
+	 * be re-ordered in in_data (const) */
+	memset(tmp_in_data, 0, 2* AES_BLOCK_SIZE);
+	memcpy(tmp_in_data, in_data + tmp_data_length, swap_length);
+
+	rc = cbccs_last_block_swap(tmp_in_data, swap_length,
+				   AES_BLOCK_SIZE, ICA_DECRYPT, variant);
+	if (rc)
+		return rc;
+
+	if (rest_data_length == 0) {
+		/* complete message handling */
+		if (tmp_data_length) {
+			rc = s390_aes_cbc(fc, tmp_data_length, in_data,
+					  iv, key, out_data);
+			if (rc)
+				return rc;
+		}
+
+		return s390_aes_cbc(fc, swap_length, tmp_in_data,
+				    iv, key, out_data + tmp_data_length);
+	}
+
+	if (tmp_data_length) {
+		rc = s390_aes_cbc(fc, tmp_data_length, in_data,
+				  iv, key, out_data);
+		if (rc)
+			return rc;
+	}
+
+	/* decrypt block C(n) with zero iv */
+	memset(tmp_iv, 0, AES_BLOCK_SIZE);
+	rc = s390_aes_cbc(fc, AES_BLOCK_SIZE,
+			  tmp_in_data + rest_data_length,
+			  tmp_iv, key, tmp_out_data);
+	if(rc)
+		return rc;
+
+	/* complete block C*(n-1) to C(n-1) and decrypt it */
+	memcpy_r_allign(tmp_in_data, AES_BLOCK_SIZE,
+			tmp_out_data, AES_BLOCK_SIZE,
+			AES_BLOCK_SIZE - rest_data_length);
+	rc = s390_aes_cbc(fc, AES_BLOCK_SIZE, tmp_in_data,
+			  iv, key, out_data + tmp_data_length);
+	if(rc)
+		return rc;
+
+	/* XOR tmp_out_data with C*(n-1) */
+	block_xor(out_data + tmp_data_length + AES_BLOCK_SIZE,
+		  tmp_in_data, tmp_out_data, rest_data_length);
+
+	return 0;
+}
+
+inline int s390_des_cbccs(unsigned int fc, const unsigned char *in_data,
+			  unsigned char *out_data, unsigned long data_length,
+			  const unsigned char *key,
+			  unsigned char *iv, unsigned int variant)
+{
+	if (s390_msa4_functions[fc].hw_fc & S390_CRYPTO_DIRECTION_MASK)
+		return s390_des_cbccs_dec(fc, in_data, out_data, data_length,
+					  key, iv, variant);
+	else
+		return s390_des_cbccs_enc(fc, in_data, out_data, data_length,
+					  key, iv, variant);
+}
+
+inline int s390_aes_cbccs(unsigned int fc, const unsigned char *in_data,
+			  unsigned char *out_data, unsigned long data_length,
+			  const unsigned char *key, unsigned int key_length,
+			  unsigned char *iv, unsigned int variant)
+{
+	if (s390_msa4_functions[fc].hw_fc & S390_CRYPTO_DIRECTION_MASK)
+		return s390_aes_cbccs_dec(fc, in_data, out_data, data_length,
+					  key, key_length, iv, variant);
+	else
+		return s390_aes_cbccs_enc(fc, in_data, out_data, data_length,
+					  key, key_length, iv, variant);
+}
--- /dev/null
+++ b/src/s390_ccm.c
@@ -0,0 +1,350 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Ruben Straus<rstraus@de.ibm.com>
+ * 	    Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2011
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include "ica_api.h"
+#include "icastats.h"
+#include "s390_crypto.h"
+#include "s390_aes.h"
+#include "s390_cmac.h"
+#include "s390_ccm.h"
+#include "s390_common.h"
+
+/* assoc_data first meta block with data
+ * for small assoc_data_length */
+struct meta_ad_small {
+	uint16_t length;
+	unsigned char data[14];
+} __attribute__((packed));
+
+/* assoc_data first meta block with prefix and data
+ * for medium assoc_data_length */
+struct meta_ad_medium {
+	unsigned char prefix[2];
+	uint32_t length;
+	unsigned char data[10];
+} __attribute__((packed));
+
+/* assoc_data first meta block with prefix and data
+ * for large assoc_data_length */
+struct meta_ad_large {
+	unsigned char prefix[2];
+	uint64_t length;
+	unsigned char data[6];
+} __attribute__((packed));
+
+/* assoc_data meta block union with size cipher block size */
+typedef union {
+	struct meta_ad_small small;
+	struct meta_ad_medium medium;
+	struct meta_ad_large large;
+} __attribute__((packed)) ad_meta_t;
+
+static inline unsigned int fc_to_key_length(unsigned int function_code)
+{
+	switch(function_code | 0x7F) {
+	case S390_CRYPTO_AES_128_ENCRYPT:
+		return 128/8;
+	case S390_CRYPTO_AES_192_ENCRYPT:
+		return 192/8;
+	case S390_CRYPTO_AES_256_ENCRYPT:
+	default:
+		return 256/8;
+	}
+}
+
+static inline void __compute_meta_b0(const unsigned char *nonce,
+				     unsigned long nonce_length,
+				     unsigned long assoc_data_length,
+				     unsigned long payload_length,
+				     unsigned long mac_length,
+				     unsigned char *meta_b0)
+{
+	struct {
+		uint8_t reserved :1;
+		uint8_t adata    :1;
+		uint8_t t_enc    :3;
+		uint8_t q_enc    :3;
+	} __attribute__((packed)) meta_flags;
+
+	memset(meta_b0, 0x00, AES_BLOCK_SIZE);
+
+	/* meta flags */
+	memset(&meta_flags, 0x00, sizeof(meta_flags));
+	if (assoc_data_length)
+		meta_flags.adata = 1;
+
+	meta_flags.t_enc = (mac_length-2) / 2;
+	meta_flags.q_enc = (15 - nonce_length) - 1;
+
+	memcpy(meta_b0, &meta_flags, sizeof(meta_flags));
+
+	/* encoding N */
+	memcpy(meta_b0 + sizeof(meta_flags), nonce, nonce_length);
+
+	/* encoding Q */
+	memcpy_r_allign(meta_b0, AES_BLOCK_SIZE,
+			&payload_length, sizeof(payload_length),
+			AES_BLOCK_SIZE - (sizeof(meta_flags) + nonce_length));
+}
+
+static inline void __compute_initial_ctr(const unsigned char *nonce,
+					 unsigned long nonce_length,
+					 unsigned long payload_length,
+					 unsigned char *ctr)
+{
+	struct {
+		uint8_t reserved :2;
+		uint8_t zero     :3;
+		uint8_t q_enc    :3;
+	} __attribute__((packed)) ctr_flags;
+
+	memset(ctr, 0x00, AES_BLOCK_SIZE);
+
+	memset(&ctr_flags, 0x00, sizeof(ctr_flags));
+	ctr_flags.q_enc = (15 - nonce_length) - 1;
+
+	memcpy(ctr, &ctr_flags, sizeof(ctr_flags));
+	memcpy(ctr + sizeof(ctr_flags), nonce, nonce_length);
+}
+
+static inline unsigned int __auth_assoc_data(unsigned int function_code,
+					     const unsigned char *assoc_data,
+					     unsigned long assoc_data_length,
+					     const unsigned char *key,
+					     unsigned int key_length,
+					     unsigned char *iv)
+{
+	unsigned int rc;
+	ad_meta_t meta;
+	unsigned char *meta_data;
+	unsigned long meta_data_length;
+	unsigned char tmp_block[AES_BLOCK_SIZE];
+	const unsigned char *rest;
+	unsigned long rest_length;
+	unsigned long head_length;
+	unsigned long tail_length;
+
+	/* preparing first block of assoc_data */
+	if (assoc_data_length < ((1ul << 16)-(1ul << 8))) {
+		meta.small.length = assoc_data_length;
+		meta_data = meta.small.data;
+		meta_data_length = sizeof(meta.small.data);
+	} else if (assoc_data_length < (1ul << 32)) {
+		meta.medium.prefix[0] = 0xff;
+		meta.medium.prefix[1] = 0xfe;
+		meta.medium.length = assoc_data_length;
+		meta_data = meta.medium.data;
+		meta_data_length = sizeof(meta.medium.data);
+	} else {
+		meta.large.prefix[0] = 0xff;
+		meta.large.prefix[1] = 0xff;
+		meta.large.length = assoc_data_length;
+		meta_data = meta.large.data;
+		meta_data_length = sizeof(meta.large.data);
+	}
+
+	if (assoc_data_length < meta_data_length) {
+		memset(meta_data, 0x00, meta_data_length);
+		memcpy(meta_data, assoc_data, assoc_data_length);
+		rest_length = 0;
+		rest = NULL;
+	} else {
+		memcpy(meta_data, assoc_data, meta_data_length);
+		rest_length = assoc_data_length - meta_data_length;
+		rest = assoc_data + meta_data_length;
+	}
+
+	/* processing first block of assoc_data */
+	rc = s390_cmac(function_code,
+		       (unsigned char *)&meta, AES_BLOCK_SIZE,
+		       key_length, key,
+		       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+		       iv);
+	if (rc)
+		return rc;
+
+	/* processing remaining assoc_data */
+	if (rest_length) {
+		tail_length = rest_length % AES_BLOCK_SIZE;
+		head_length = rest_length - tail_length;
+
+		if (head_length) {
+			rc = s390_cmac(function_code,
+				       rest, head_length,
+				       key_length, key,
+				       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+				       iv);
+			if (rc)
+				return rc;
+
+			rest += head_length;
+		}
+
+		/* assoc_data padding */
+		if (tail_length) {
+			memset(tmp_block, 0x00, AES_BLOCK_SIZE);
+			memcpy(tmp_block, rest, tail_length);
+
+			rc = s390_cmac(function_code,
+				       tmp_block, AES_BLOCK_SIZE,
+				       key_length, key,
+				       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+				       iv);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int s390_ccm_authenticate(unsigned int function_code,
+					  const unsigned char *payload,
+					  unsigned long payload_length,
+					  const unsigned char *assoc_data,
+					  unsigned long assoc_data_length,
+					  const unsigned char *nonce,
+					  unsigned int nonce_length,
+					  unsigned char *tag,
+					  unsigned int tag_length,
+					  const unsigned char *key,
+					  unsigned int key_length)
+{
+	unsigned int rc;
+	unsigned char meta_b0[AES_BLOCK_SIZE];
+	unsigned char tmp_block[AES_BLOCK_SIZE];
+	unsigned long head_length;
+	unsigned long tail_length;
+
+	/* compute meta information block B0 */
+	__compute_meta_b0(nonce, nonce_length,
+			  assoc_data_length, payload_length, tag_length,
+			  meta_b0);
+
+	/* kmac of first block (intermediate) */
+	memset(tag, 0x00, AES_BLOCK_SIZE);
+	rc = s390_cmac(function_code,
+		       meta_b0, AES_BLOCK_SIZE,
+		       key_length, key,
+		       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+		       tag);
+	if (rc)
+		return rc;
+
+	/* kmac of assoc_data blocks (intermediate) */
+	if (assoc_data_length) {
+		rc = __auth_assoc_data(function_code,
+				       assoc_data, assoc_data_length,
+				       key, key_length,
+				       tag);
+		if (rc)
+			return rc;
+	}
+
+	/* kmac of payload (intermediate) */
+	tail_length = payload_length % AES_BLOCK_SIZE;
+	head_length = payload_length - tail_length;
+
+	if (head_length) {
+		rc = s390_cmac(function_code,
+			       payload, head_length,
+			       key_length, key,
+			       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+			       tag);
+		if (rc)
+			return rc;
+	}
+
+	if (tail_length) {
+		memset(tmp_block, 0x00, AES_BLOCK_SIZE);
+		memcpy(tmp_block, payload + head_length, tail_length);
+
+		rc = s390_cmac(function_code,
+			       tmp_block, AES_BLOCK_SIZE,
+			       key_length, key,
+			       AES_BLOCK_SIZE, NULL,	/* cmac_intermediate */
+			       tag);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+unsigned int s390_ccm(unsigned int function_code,
+		      unsigned char *payload, unsigned long payload_length,
+		      unsigned char *ciphertext,
+		      const unsigned char *assoc_data, unsigned long assoc_data_length,
+		      const unsigned char *nonce, unsigned long nonce_length,
+		      unsigned char *mac, unsigned long mac_length,
+		      const unsigned char *key)
+{
+	unsigned char initial_ctr[AES_BLOCK_SIZE];
+	unsigned char cipher_ctr[AES_BLOCK_SIZE];
+	unsigned char tag[AES_BLOCK_SIZE];
+	unsigned int ccm_ctr_width;
+	unsigned int hardware;
+	unsigned int rc;
+
+	hardware = 1;
+
+	/* compute initial counter */
+	__compute_initial_ctr(nonce, nonce_length, payload_length, initial_ctr);
+	ccm_ctr_width = (15 - nonce_length) * 8;
+
+	if (payload_length) {
+		/* compute counter for en-/decryption */
+		memcpy(cipher_ctr, initial_ctr, AES_BLOCK_SIZE);
+		ctr_inc_single(cipher_ctr, AES_BLOCK_SIZE, ccm_ctr_width);
+
+		/* en-/decrypt */
+		if (function_code % 2) {
+			/* decrypt */
+			rc = s390_aes_ctr(UNDIRECTED_FC(function_code),
+					  ciphertext, payload, payload_length,
+					  key, cipher_ctr, ccm_ctr_width);
+			if (rc)
+				return rc;
+
+			stats_increment(ICA_STATS_CCM_DECRYPT, hardware);
+		} else {
+			/*encrypt */
+			rc = s390_aes_ctr(UNDIRECTED_FC(function_code),
+					  payload, ciphertext, payload_length,
+					  key, cipher_ctr, ccm_ctr_width);
+			if (rc)
+				return rc;
+
+			stats_increment(ICA_STATS_CCM_ENCRYPT, hardware);
+		}
+	}
+
+	/* generate tag */
+	rc = s390_ccm_authenticate(UNDIRECTED_FC(function_code),
+				   payload, payload_length,
+				   assoc_data, assoc_data_length,
+				   nonce, nonce_length,
+				   tag, mac_length,
+				   key, fc_to_key_length(function_code));
+	if (rc)
+		return rc;
+
+	/* encrypt tag into mac */
+	return s390_aes_ctr(UNDIRECTED_FC(function_code),
+			    tag, mac, mac_length,
+			    key, initial_ctr, ccm_ctr_width);
+}
+
--- a/src/s390_cmac.c
+++ b/src/s390_cmac.c
@@ -20,57 +20,160 @@
 #include "init.h"
 #include "s390_crypto.h"
 #include "s390_aes.h"
+#include "s390_des.h"
 #include "s390_cmac.h"
 
-#define block_size 16
+#define PARM_BLOCK_SIZE 72
+
+/*
+struct cmac_des_parm_block{
+	uint8_t ml;
+	unsigned char reserved[7];
+	unsigned char message[DES_BLOCK_SIZE];
+	ica_des_vector_t iv;
+	unsigned char keys[3*DES_BLOCK_SIZE];
+} __attribute__((packed));
+
+struct cmac_aes_parm_block {
+	uint8_t ml;
+	unsigned char reserved[7];
+	unsigned char message[AES_BLOCK_SIZE];
+	ica_aes_vector_t iv;
+	ica_aes_key_len_256_t keys;
+} __attribute__((packed));
+
+static inline void parm_block_lookup_init2(struct parm_block_lookup *lookup,
+					   unsigned char *base,
+					   unsigned int block_size)
+{
+	lookup->block_size = block_size;
+	lookup->base = base;
+
+	switch (block_size) {
+	case DES_BLOCK_SIZE: {
+		struct cmac_des_parm_block *tmp = (struct cmac_des_parm_block *)&base;
+		lookup->ml      = &(tmp->ml);
+		lookup->message = tmp->message;
+		lookup->iv      = tmp->iv;
+		lookup->keys    = (unsigned char *)tmp->keys;
+		break; }
+	case AES_BLOCK_SIZE:
+	default: {
+		struct cmac_aes_parm_block *tmp = (struct cmac_aes_parm_block *)&base;
+		lookup->ml      = &(tmp->ml);
+		lookup->message = tmp->message;
+		lookup->iv      = tmp->iv;
+		lookup->keys    = tmp->keys;
+		break; }
+	}
+}
+*/
+
+typedef unsigned char parm_block_t[PARM_BLOCK_SIZE];
+
+struct parm_block_lookup {
+	unsigned int block_size;
+	unsigned char *base;
+	uint8_t       *ml;
+	unsigned char *message;
+	unsigned char *iv;
+	unsigned char *keys;
+};
+
+static inline void parm_block_lookup_init(struct parm_block_lookup *lookup,
+					  parm_block_t base,
+					  unsigned int block_size)
+{
+	lookup->block_size = block_size;
+	lookup->base       = base;
+	lookup->ml         = (uint8_t *)base;
+	lookup->message    = (unsigned char *)(base + 8);
+	lookup->iv         = (unsigned char *)(lookup->message + block_size);
+	lookup->keys       = (unsigned char *)(lookup->iv + block_size);
+}
+
+static unsigned int fc_block_size(unsigned int fc)
+{
+	unsigned int rc;
+
+	switch(fc) {
+	case S390_CRYPTO_DEA_ENCRYPT:
+	case S390_CRYPTO_TDEA_128_ENCRYPT:
+	case S390_CRYPTO_TDEA_192_ENCRYPT:
+		rc = DES_BLOCK_SIZE;
+		break;
+	case S390_CRYPTO_AES_128_ENCRYPT:
+	case S390_CRYPTO_AES_192_ENCRYPT:
+	case S390_CRYPTO_AES_256_ENCRYPT:
+	default:
+		rc = AES_BLOCK_SIZE;
+		break;
+	}
+
+	return rc;
+}
 
 static int s390_cmac_hw(unsigned long fc,
 			const unsigned char *message,
 			unsigned long message_length,
 			unsigned int  key_size, const unsigned char *key,
-			unsigned int cmac_length, unsigned char *cmac)
+			unsigned int cmac_length, unsigned char *cmac,
+			unsigned char *iv)
 {
-	struct {
-		unsigned int ml :8;   /* 8 bit unsigned message length */
-		unsigned char reserved[7];
-		unsigned char message[AES_BLOCK_SIZE];
-		ica_aes_vector_t iv;
-		ica_aes_key_len_256_t keys;
-	} __attribute__((packed)) aes_parm_block;
+	parm_block_t parm_block;
+	struct parm_block_lookup pb_lookup;
 	unsigned int length_tail;
 	unsigned long length_head;
 	int rc;
 
 	/* CMAC uses encrypt function code for generate and verify. */
 	fc &= S390_CRYPTO_FUNCTION_MASK;
-	memset(&aes_parm_block, 0, sizeof(aes_parm_block));
-	memcpy(&(aes_parm_block.keys), key, key_size);
+	memset(parm_block, 0, sizeof(parm_block));
 
-	if (message_length) {
-		length_tail = message_length % AES_BLOCK_SIZE;
-		if (length_tail)
-			length_head = message_length - length_tail;
-		else {
-			length_head = message_length - AES_BLOCK_SIZE;
-			length_tail = AES_BLOCK_SIZE;
-		}
+	parm_block_lookup_init(&pb_lookup, parm_block, fc_block_size(fc));
+	memcpy(pb_lookup.keys, key, key_size);
 
-		if (length_head) {
-			rc = s390_kmac(fc, &(aes_parm_block.iv),
-				       message, length_head);
-			if (rc < 0)
-				return EIO;
+	/* copy iv into param block, if available (intermediate) */
+	if (iv != NULL)
+		memcpy(pb_lookup.iv, iv, pb_lookup.block_size);
+
+
+	if (cmac == NULL) {
+		/* intermediate */
+		rc = s390_kmac(fc, pb_lookup.iv, message, message_length);
+		if (rc < 0)
+			return rc;
+
+		/* rescue iv for chained calls (intermediate) */
+		memcpy(iv, pb_lookup.iv, pb_lookup.block_size);
+	} else {
+		if (message_length) {
+			length_tail = message_length % pb_lookup.block_size;
+			if (length_tail)
+				length_head = message_length - length_tail;
+			else {
+				length_head = message_length - pb_lookup.block_size;
+				length_tail = pb_lookup.block_size;
+			}
+
+			if (length_head) {
+				rc = s390_kmac(fc, pb_lookup.iv,
+					       message, length_head);
+				if (rc < 0)
+					return EIO;
+			}
+
+			*pb_lookup.ml = length_tail * 8;	/* message length in bits */
+			memcpy(pb_lookup.message, message + length_head, length_tail);
 		}
+		/* calculate final block (last/full) */
+		rc = s390_pcc(fc, pb_lookup.base);
+		if (rc < 0)
+			return EIO;
 
-		aes_parm_block.ml = length_tail * 8;	/* message length in bits */
-		memcpy(&(aes_parm_block.message), message + length_head, length_tail);
+		memcpy(cmac, pb_lookup.iv, cmac_length);
 	}
 
-	rc = s390_pcc(fc, &aes_parm_block);
-	if (rc < 0)
-		return EIO;
-
-	memcpy(cmac, &(aes_parm_block.iv), cmac_length);
 	return 0;
 }
 
@@ -78,7 +181,8 @@ inline int s390_cmac(unsigned long fc,
 		     const unsigned char *message,
 		     unsigned long message_length,
 		     unsigned int  key_length, const unsigned char *key,
-		     unsigned int  mac_length, unsigned char *mac)
+		     unsigned int  mac_length, unsigned char *mac,
+		     unsigned char *iv)
 {
 	int hardware = 1;
 	int rc;
@@ -87,7 +191,8 @@ inline int s390_cmac(unsigned long fc,
 		rc = s390_cmac_hw(s390_msa4_functions[fc].hw_fc,
 				  message, message_length,
 				  key_length, key,
-				  mac_length, mac);
+				  mac_length, mac,
+				  iv);
 	else {
 		hardware = 0;
 		return EPERM;
--- /dev/null
+++ b/src/s390_common.c
@@ -0,0 +1,104 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2011, 2012
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "ica_api.h"
+#include "icastats.h"
+#include "init.h"
+#include "s390_crypto.h"
+#include "s390_aes.h"
+#include "s390_des.h"
+#include "s390_aux.h"
+#include "s390_common.h"
+
+typedef struct {
+	u_int64_t upper_half;
+	u_int64_t lower_half;
+} ctr128_t;
+
+static inline void __inc(ctr128_t *ctr)
+{
+	if (!(++(ctr->lower_half)))
+		(ctr->upper_half)++;
+}
+
+void ctr_inc_block(unsigned char *iv, unsigned int block_size,
+		   unsigned int ctr_width, unsigned char *ctrlist,
+		   unsigned long ctrlist_length)
+{
+	ctr128_t tmp_ctr = { 0ul, 0ul };
+	unsigned char *dest;
+	unsigned int ctr_byte_width;
+
+	ctr_byte_width = ctr_width / 8;
+
+	// init counter with iv
+	memcpy_r_allign((void *)&tmp_ctr, sizeof(tmp_ctr),
+			iv, block_size, block_size);
+
+	for (dest = ctrlist;
+	     dest < (ctrlist + ctrlist_length);
+	     dest += block_size) {
+		// copy nounce to ctrlist
+		memcpy(dest, iv, block_size - ctr_byte_width);
+
+		// add counter values to ctrlist
+		memcpy_r_allign(dest, block_size, (void *)&tmp_ctr,
+				sizeof(tmp_ctr), ctr_byte_width);
+		__inc(&tmp_ctr);
+	}
+
+	// update iv for chaining
+	memcpy_r_allign(iv, block_size, (void *)&tmp_ctr,
+			  sizeof(tmp_ctr), ctr_byte_width);
+}
+
+void ctr_inc_single(unsigned char *iv, unsigned int block_size,
+			   unsigned int ctr_width)
+{
+	ctr128_t tmp_ctr = { 0ul, 0ul };
+	unsigned int ctr_byte_width;
+
+	ctr_byte_width = ctr_width / 8;
+
+	// init counter with iv
+	memcpy_r_allign((void *)&tmp_ctr, sizeof(tmp_ctr), iv, block_size, block_size);
+
+	__inc(&tmp_ctr);
+
+	// update iv for chaining
+	memcpy_r_allign(iv, block_size, (void *)&tmp_ctr, sizeof(tmp_ctr), ctr_byte_width);
+}
+
+inline void memcpy_r_allign(void *dest, int dest_bs,
+			    void *src, int src_bs, int size)
+{
+	memcpy(dest + (dest_bs - size), src + (src_bs - size), size);
+}
+
+inline void block_xor(unsigned char dest[],
+		      unsigned char a[], unsigned char b[],
+		      unsigned int length)
+{
+	unsigned int i;
+	for (i = 0; i < length; i++) {
+		dest[i] = a[i] ^ b[i];
+	}
+}
+
+
+
--- a/src/s390_ctr.c
+++ b/src/s390_ctr.c
@@ -24,77 +24,13 @@
 #include "s390_aes.h"
 #include "s390_des.h"
 #include "s390_aux.h"
+#include "s390_common.h"
 
 /* get next multiple of blocksize (bs) of n */
 #define NEXT_BS(n, bs) ((n + (bs - 1)) & (~(bs - 1)))
 
 #define LARGE_MSG_CHUNK 4096	/* page size */
 
-typedef struct {
-	u_int64_t upper_half;
-	u_int64_t lower_half;
-} ctr128_t;
-
-static inline void __memcpy_r_allign(void *dest, int dest_bs,
-					   void *src, int src_bs, int size)
-{
-	memcpy(dest + (dest_bs - size), src + (src_bs - size), size);
-}
-
-static inline void __inc(ctr128_t *ctr)
-{
-	if (!(++(ctr->lower_half)))
-		(ctr->upper_half)++;
-}
-
-static void ctr_inc_block(unsigned char *iv, unsigned int block_size,
-			  unsigned int ctr_width, unsigned char *ctrlist,
-			  unsigned long ctrlist_length)
-{
-	ctr128_t tmp_ctr = { 0ul, 0ul };
-	unsigned char *dest;
-	unsigned int ctr_byte_width;
-
-	ctr_byte_width = ctr_width / 8;
-
-	// init counter with iv
-	__memcpy_r_allign((void *)&tmp_ctr, sizeof(tmp_ctr),
-			  iv, block_size, block_size);
-
-	for (dest = ctrlist;
-	     dest < (ctrlist + ctrlist_length);
-	     dest += block_size) {
-		// copy nounce to ctrlist
-		memcpy(dest, iv, block_size - ctr_byte_width);
-
-		// add counter values to ctrlist
-		__memcpy_r_allign(dest, block_size, (void *)&tmp_ctr,
-				  sizeof(tmp_ctr), ctr_byte_width);
-		__inc(&tmp_ctr);
-	}
-
-	// update iv for chaining
-	__memcpy_r_allign(iv, block_size, (void *)&tmp_ctr,
-			  sizeof(tmp_ctr), ctr_byte_width);
-}
-
-static void ctr_inc_single(unsigned char *iv, unsigned int block_size,
-			   unsigned int ctr_width)
-{
-	ctr128_t tmp_ctr = { 0ul, 0ul };
-	unsigned int ctr_byte_width;
-
-	ctr_byte_width = ctr_width / 8;
-
-	// init counter with iv
-	__memcpy_r_allign((void *)&tmp_ctr, sizeof(tmp_ctr), iv, block_size, block_size);
-
-	__inc(&tmp_ctr);
-
-	// update iv for chaining
-	__memcpy_r_allign(iv, block_size, (void *)&tmp_ctr, sizeof(tmp_ctr), ctr_byte_width);
-}
-
 inline int s390_ctr_hw(unsigned int function_code, unsigned long data_length,
                        const unsigned char *in_data, const unsigned char *key,
                        unsigned char *out_data, const unsigned char *ctrlist)
--- /dev/null
+++ b/src/s390_gcm.c
@@ -0,0 +1,279 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/**
+ * Authors: Felix Beck <felix.beck@de.ibm.com>
+ *	    Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * Copyright IBM Corp. 2010,2011
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "s390_crypto.h"
+#include "s390_aes.h"
+#include "s390_gcm.h"
+#include "s390_common.h"
+#include "icastats.h"
+
+/* the recommended iv length for GCM is 96 bit or 12 byte */
+#define GCM_RECOMMENDED_IV_LENGTH 12
+
+/* ctr with for GCM is specified with 32 bit */
+#define GCM_CTR_WIDTH 32
+
+/* Helper struct containing last uncomplete ciphertext block
+ * with padding, aad_length and ciphertext_length. */
+unsigned char zero_block[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char partial_j[] = {
+	0x00, 0x00, 0x00, 0x01,
+};
+
+struct pad_meta {
+	unsigned char pad[AES_BLOCK_SIZE];
+	uint64_t length_a;
+	uint64_t length_b;
+} __attribute__((packed));
+
+static inline unsigned int __compute_j0(const unsigned char *iv,
+					unsigned int iv_length,
+					const unsigned char *subkey_h,
+					unsigned char *j0)
+{
+	int rc;
+	struct pad_meta iv_pad_meta;
+	unsigned long head_length;
+	unsigned long tail_length;
+
+	/* iv_length of 12 bytes is recommended */
+	if (iv_length == GCM_RECOMMENDED_IV_LENGTH) {
+		memcpy(j0, iv, iv_length);
+		memcpy(j0 + iv_length, partial_j, sizeof(partial_j));
+		return 0;
+	}
+
+	memset(j0, 0x00, AES_BLOCK_SIZE);
+
+	memset(iv_pad_meta.pad, 0x00, sizeof(iv_pad_meta.pad));
+	iv_pad_meta.length_a = (uint64_t)0ul;	/* unused for j0 */
+	iv_pad_meta.length_b = (uint64_t)(iv_length * 8ul);
+
+	tail_length = iv_length % AES_BLOCK_SIZE;
+	head_length = iv_length - tail_length;
+
+	if (head_length) {
+		rc = s390_ghash(iv, head_length, subkey_h, j0);
+		if (rc)
+			return rc;
+	}
+
+	if (tail_length) {
+		memcpy(iv_pad_meta.pad, iv + head_length, tail_length);
+		rc = s390_ghash((unsigned char *)&iv_pad_meta,
+				sizeof(iv_pad_meta),
+				subkey_h, j0);
+		if (rc)
+			return rc;
+	} else {
+		/* no padding necessary, only ghash meta information */
+		rc = s390_ghash((unsigned char *)&iv_pad_meta.length_a,
+				AES_BLOCK_SIZE,
+				subkey_h, j0);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static inline int s390_ghash_hw(unsigned int fc,
+				const unsigned char *in_data,
+				unsigned long data_length,
+				unsigned char *iv,
+				const unsigned char *subkey)
+{
+	struct {
+		unsigned char iv[AES_BLOCK_SIZE];
+		unsigned char hash_subkey[AES_BLOCK_SIZE];
+	} __attribute__((packed)) parmblock;
+	int rc = 0;
+
+	memcpy(parmblock.iv, iv, AES_BLOCK_SIZE);
+	memcpy(parmblock.hash_subkey, subkey, AES_BLOCK_SIZE);
+
+	rc = s390_kimd(fc, &parmblock, in_data, data_length);
+	if(rc == data_length) {
+		/* All data has been processed */
+		memcpy(iv, parmblock.iv, AES_BLOCK_SIZE);
+		return 0;
+	}
+
+	return EIO;
+}
+
+static unsigned int s390_gcm_authenticate(const unsigned char *ciphertext, unsigned long text_length,
+					  const unsigned char *aad, unsigned long aad_length,
+					  const unsigned char *subkey_h, unsigned char *iv)
+{
+	unsigned int rc;
+	unsigned char aad_pad[AES_BLOCK_SIZE];
+	unsigned long head_length;
+	unsigned long tail_length;
+	struct pad_meta c_pad_meta;
+
+	memset(iv, 0x00, AES_BLOCK_SIZE);
+
+	memset(c_pad_meta.pad, 0x00, sizeof(c_pad_meta.pad));
+	c_pad_meta.length_a = (uint64_t)(aad_length * 8ul);
+	c_pad_meta.length_b = (uint64_t)(text_length * 8ul);
+
+	if (aad_length) {
+		tail_length = aad_length % AES_BLOCK_SIZE;
+		head_length = aad_length - tail_length;
+
+		/* ghash aad head */
+		if (head_length) {
+			rc = s390_ghash(aad, head_length, subkey_h, iv);
+			if (rc)
+				return rc;
+		}
+
+		/* ghash aad tail */
+		if (tail_length) {
+			memset(aad_pad, 0x00, AES_BLOCK_SIZE);
+			memcpy(aad_pad, aad + head_length, tail_length);
+
+			rc = s390_ghash(aad_pad, AES_BLOCK_SIZE, subkey_h, iv);
+			if (rc)
+				return rc;
+		}
+	}
+
+	if (text_length) {
+		tail_length = text_length % AES_BLOCK_SIZE;
+		head_length = text_length - tail_length;
+
+		/* ghash ciphertext head */
+		if (head_length) {
+			rc = s390_ghash(ciphertext, head_length, subkey_h, iv);
+			if (rc)
+				return rc;
+		}
+
+		/* ghash ciphertext tail and meta data */
+		if (tail_length) {
+			memcpy(c_pad_meta.pad, ciphertext + head_length, tail_length);
+
+			rc = s390_ghash((unsigned char *)&c_pad_meta,
+					sizeof(c_pad_meta), subkey_h, iv);
+			if (rc)
+				return rc;
+		} else {
+			rc = s390_ghash((unsigned char *)&c_pad_meta.length_a,
+					AES_BLOCK_SIZE, subkey_h, iv);
+			if (rc)
+				return rc;
+		}
+	} else {
+		/* ghash meta data only */
+		rc = s390_ghash((unsigned char *)&c_pad_meta.length_a,
+				AES_BLOCK_SIZE,
+				subkey_h, iv);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+inline int s390_ghash(const unsigned char *in_data, unsigned long data_length,
+		      const unsigned char *key, unsigned char *iv)
+{
+	if (!s390_kimd_functions[GHASH].enabled)
+		return EPERM;
+
+	return s390_ghash_hw(s390_kimd_functions[GHASH].hw_fc,
+			     in_data, data_length,
+			     iv, key);
+}
+
+int s390_gcm(unsigned int function_code,
+	     unsigned char *plaintext, unsigned long text_length,
+	     unsigned char *ciphertext,
+	     const unsigned char *iv, unsigned long iv_length,
+	     const unsigned char *aad, unsigned long aad_length,
+	     unsigned char *tag, unsigned long tag_length,
+	     const unsigned char *key)
+{
+	unsigned char subkey_h[AES_BLOCK_SIZE];
+	unsigned char j0[AES_BLOCK_SIZE];
+	unsigned char tmp_ctr[AES_BLOCK_SIZE];
+	/* temporary tag must be of size cipher block size */
+	unsigned char tmp_tag[AES_BLOCK_SIZE];
+	unsigned int hardware;
+	unsigned int rc;
+
+	if (!msa4_switch)
+		return EPERM;
+
+	hardware = 1;
+
+	/* calculate subkey H */
+	rc = s390_aes_ecb(UNDIRECTED_FC(function_code),
+			  AES_BLOCK_SIZE, zero_block,
+			  key, subkey_h);
+	if (rc)
+		return rc;
+
+	/* calculate initial counter, based on iv */
+	__compute_j0(iv, iv_length, subkey_h, j0);
+
+	/* prepate initial counter for cipher */
+	memcpy(tmp_ctr, j0, AES_BLOCK_SIZE);
+	ctr_inc_single(tmp_ctr, AES_BLOCK_SIZE, GCM_CTR_WIDTH);
+
+	/* en-/decrypt payload */
+	if (function_code % 2) {
+		/* decrypt */
+		rc = s390_aes_ctr(UNDIRECTED_FC(function_code),
+				  ciphertext, plaintext, text_length,
+				  key, tmp_ctr, GCM_CTR_WIDTH);
+		if (rc)
+			return rc;
+
+		stats_increment(ICA_STATS_GCM_DECRYPT, hardware);
+	} else {
+		/* encrypt */
+		rc = s390_aes_ctr(UNDIRECTED_FC(function_code),
+				  plaintext, ciphertext, text_length,
+				  key, tmp_ctr, GCM_CTR_WIDTH);
+		if (rc)
+			return rc;
+
+		stats_increment(ICA_STATS_GCM_ENCRYPT, hardware);
+	}
+
+	/* generate authentication tag */
+	rc = s390_gcm_authenticate(ciphertext, text_length,
+				   aad, aad_length,
+				   subkey_h, tmp_tag);
+	if (rc)
+		return rc;
+
+	stats_increment(ICA_STATS_GCM_AUTH, hardware);
+
+	/* encrypt tag */
+	return s390_aes_ctr(UNDIRECTED_FC(function_code),
+			    tmp_tag, tag, tag_length,
+			    key, j0, GCM_CTR_WIDTH);
+}
+
--- a/src/tests/Makefile.linux
+++ b/src/tests/Makefile.linux
@@ -12,14 +12,13 @@ TARGETS = libica_des_test libica_3des_te
           libica_rsa_test libica_rng_test libica_keygen_test \
 	  test_mech_list \
 	  libica_cmac_test \
-	  libica_aes_xts_test \
+	  libica_aes_xts_test libica_aes_gcm_test libica_ccm_test \
 	  libica_aes_ctr_test libica_aes_ofb_test libica_aes_cfb_test \
 	  libica_aes_cbc_test libica_aes_ecb_test \
-	  libica_3des_ecb_test \
+	  libica_des_ecb_test libica_cbccs_test libica_3des_ecb_test \
 	  libica_des_ctr_test libica_3des_ctr_test \
 	  libica_des_cfb_test libica_3des_cfb_test \
 	  libica_des_cbc_test libica_3des_cbc_test \
-	  libica_des_ecb_test libica_3des_ecb_test \
 	  libica_des_ofb_test libica_3des_ofb_test \
 	  libica_get_version
 
--- /dev/null
+++ b/src/tests/libica_aes_gcm_test.c
@@ -0,0 +1,846 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/* (C) COPYRIGHT International Business Machines Corp. 2011          */
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "ica_api.h"
+
+#define NR_TESTS 12
+
+
+/* GCM data - 1*/
+unsigned char NIST_KEY_GCM_E1[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E1[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
+};
+
+unsigned char NIST_AAD_GCM_E1[] = {
+};
+
+unsigned char NIST_IV_GCM_E1[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E1[] = {
+	0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+	0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E1[] = {
+	0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+	0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+	0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+	0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+	0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+	0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+	0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+	0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85,
+};
+
+/* GCM data - 2*/
+unsigned char NIST_KEY_GCM_E2[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E2[] = {
+};
+
+unsigned char NIST_AAD_GCM_E2[] = {
+};
+
+unsigned char NIST_IV_GCM_E2[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E2[] = {
+	0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+	0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E2[] = {
+};
+
+/* GCM data - 3*/
+unsigned char NIST_KEY_GCM_E3[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E3[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_AAD_GCM_E3[] = {
+};
+
+unsigned char NIST_IV_GCM_E3[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E3[] = {
+	0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
+	0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E3[] = {
+	0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+	0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78,
+};
+
+/* GCM data - 4*/
+unsigned char NIST_KEY_GCM_E4[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E4[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39,
+};
+
+unsigned char NIST_AAD_GCM_E4[] = {
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xab, 0xad, 0xda, 0xd2,
+};
+
+unsigned char NIST_IV_GCM_E4[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E4[] = {
+	0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+	0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E4[] = {
+	0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+	0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+	0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+	0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+	0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+	0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+	0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+	0x3d, 0x58, 0xe0, 0x91,
+};
+
+/* GCM data - 5 - AES 192 - Test Case 7*/
+unsigned char NIST_KEY_GCM_E5[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E5[] = {
+};
+
+unsigned char NIST_AAD_GCM_E5[] = {
+};
+
+unsigned char NIST_IV_GCM_E5[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E5[] = {
+	0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
+	0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E5[] = {
+};
+
+/* GCM data - 6 - AES 192 - Test Case 8*/
+unsigned char NIST_KEY_GCM_E6[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E6[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_AAD_GCM_E6[] = {
+};
+
+unsigned char NIST_IV_GCM_E6[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E6[] = {
+	0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
+	0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E6[] = {
+	0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+	0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00,
+};
+
+/* GCM data - 7 - AES 192 - Test Case 9*/
+unsigned char NIST_KEY_GCM_E7[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E7[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
+};
+
+unsigned char NIST_AAD_GCM_E7[] = {
+};
+
+unsigned char NIST_IV_GCM_E7[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E7[] = {
+	0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
+	0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E7[] = {
+	0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+	0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+	0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+	0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+	0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+	0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+	0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+	0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56,
+};
+
+/* GCM data - 8 - AES 192 - Test Case 10*/
+unsigned char NIST_KEY_GCM_E8[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E8[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39,
+};
+
+unsigned char NIST_AAD_GCM_E8[] = {
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xab, 0xad, 0xda, 0xd2,
+};
+
+unsigned char NIST_IV_GCM_E8[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E8[] = {
+	0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
+	0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E8[] = {
+	0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+	0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+	0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+	0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+	0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+	0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+	0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+	0xcc, 0xda, 0x27, 0x10,
+};
+
+/* GCM data - 9 - AES 256 - Test Case 13*/
+unsigned char NIST_KEY_GCM_E9[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E9[] = {
+};
+
+unsigned char NIST_AAD_GCM_E9[] = {
+};
+
+unsigned char NIST_IV_GCM_E9[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E9[] = {
+	0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
+	0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E9[] = {
+};
+
+/* GCM data - 10 - AES 256 - Test Case 14*/
+unsigned char NIST_KEY_GCM_E10[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E10[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_AAD_GCM_E10[] = {
+};
+
+unsigned char NIST_IV_GCM_E10[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+unsigned char NIST_TAG_GCM_E10[] = {
+	0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
+	0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E10[] = {
+	0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
+	0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18,
+};
+
+/* GCM data - 11 - AES 256 - Test Case 15*/
+unsigned char NIST_KEY_GCM_E11[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E11[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
+};
+
+unsigned char NIST_AAD_GCM_E11[] = {
+};
+
+unsigned char NIST_IV_GCM_E11[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E11[] = {
+	0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
+	0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E11[] = {
+	0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+	0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+	0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+	0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+	0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+	0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+	0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+	0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad,
+};
+
+/* GCM data */
+unsigned char NIST_KEY_GCM_E12[] = {
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+	0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+	0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+};
+
+unsigned char NIST_TEST_DATA_GCM_E12[] = {
+	0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+	0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+	0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+	0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+	0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+	0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+	0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+	0xba, 0x63, 0x7b, 0x39,
+};
+
+unsigned char NIST_AAD_GCM_E12[] = {
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+	0xab, 0xad, 0xda, 0xd2,
+};
+
+unsigned char NIST_IV_GCM_E12[] = {
+	0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+	0xde, 0xca, 0xf8, 0x88,
+};
+
+unsigned char NIST_TAG_GCM_E12[] = {
+	0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
+	0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b,
+};
+
+unsigned char NIST_TEST_RESULT_GCM_E12[] = {
+	0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+	0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+	0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+	0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+	0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+	0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+	0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+	0xbc, 0xc9, 0xf6, 0x62,
+};
+
+
+
+void dump_array(unsigned char *ptr, unsigned int size)
+{
+	unsigned char *ptr_end;
+	unsigned char *h;
+	int i = 1;
+
+	h = ptr;
+	ptr_end = ptr + size;
+	while (h < ptr_end) {
+		printf("0x%02x ",*h);
+		h++;
+		if (i == 8) {
+			printf("\n");
+			i = 1;
+		} else {
+			++i;
+		}
+	}
+	printf("\n");
+}
+
+void dump_gcm_data(unsigned char *iv, unsigned int iv_length,
+                   unsigned char *aad, unsigned int aad_length,
+                   unsigned char *key, unsigned int key_length,
+                   unsigned char *input_data, unsigned int data_length,
+                   unsigned char *output_data,
+                   unsigned char *t, unsigned int t_size)
+{
+	printf("IV \n");
+	dump_array(iv, iv_length);
+	printf("AAD \n");
+	dump_array(aad, aad_length);
+	printf("Key \n");
+	dump_array(key, key_length);
+	printf("Input Data\n");
+	dump_array(input_data, data_length);
+	printf("Output Data\n");
+	dump_array(output_data, data_length);
+	printf("T\n");
+	dump_array(t, t_size);
+}
+
+void get_sizes(unsigned int *aad_length, unsigned int *data_length,
+	       unsigned int *t_length, unsigned int *iv_length,
+	       unsigned int *key_length, unsigned int iteration)
+{
+	switch (iteration) {
+		case 1:
+			*aad_length = sizeof(NIST_AAD_GCM_E1);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E1);
+			*t_length = sizeof(NIST_TAG_GCM_E1);
+			*iv_length = sizeof(NIST_IV_GCM_E1);
+			*key_length = sizeof(NIST_KEY_GCM_E1);
+			break;
+		case 2:
+			*aad_length = sizeof(NIST_AAD_GCM_E2);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E2);
+			*t_length = sizeof(NIST_TAG_GCM_E2);
+			*iv_length = sizeof(NIST_IV_GCM_E2);
+			*key_length = sizeof(NIST_KEY_GCM_E2);
+			break;
+		case 3:
+			*aad_length = sizeof(NIST_AAD_GCM_E3);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E3);
+			*t_length = sizeof(NIST_TAG_GCM_E3);
+			*iv_length = sizeof(NIST_IV_GCM_E3);
+			*key_length = sizeof(NIST_KEY_GCM_E3);
+			break;
+		case 4:
+			*aad_length = sizeof(NIST_AAD_GCM_E4);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E4);
+			*t_length = sizeof(NIST_TAG_GCM_E4);
+			*iv_length = sizeof(NIST_IV_GCM_E4);
+			*key_length = sizeof(NIST_KEY_GCM_E4);
+			break;
+		case 5:
+			*aad_length = sizeof(NIST_AAD_GCM_E5);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E5);
+			*t_length = sizeof(NIST_TAG_GCM_E5);
+			*iv_length = sizeof(NIST_IV_GCM_E5);
+			*key_length = sizeof(NIST_KEY_GCM_E5);
+			break;
+		case 6:
+			*aad_length = sizeof(NIST_AAD_GCM_E6);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E6);
+			*t_length = sizeof(NIST_TAG_GCM_E6);
+			*iv_length = sizeof(NIST_IV_GCM_E6);
+			*key_length = sizeof(NIST_KEY_GCM_E6);
+			break;
+		case 7:
+			*aad_length = sizeof(NIST_AAD_GCM_E7);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E7);
+			*t_length = sizeof(NIST_TAG_GCM_E7);
+			*iv_length = sizeof(NIST_IV_GCM_E7);
+			*key_length = sizeof(NIST_KEY_GCM_E7);
+			break;
+		case 8:
+			*aad_length = sizeof(NIST_AAD_GCM_E8);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E8);
+			*t_length = sizeof(NIST_TAG_GCM_E8);
+			*iv_length = sizeof(NIST_IV_GCM_E8);
+			*key_length = sizeof(NIST_KEY_GCM_E8);
+			break;
+		case 9:
+			*aad_length = sizeof(NIST_AAD_GCM_E9);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E9);
+			*t_length = sizeof(NIST_TAG_GCM_E9);
+			*iv_length = sizeof(NIST_IV_GCM_E9);
+			*key_length = sizeof(NIST_KEY_GCM_E9);
+			break;
+		case 10:
+			*aad_length = sizeof(NIST_AAD_GCM_E10);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E10);
+			*t_length = sizeof(NIST_TAG_GCM_E10);
+			*iv_length = sizeof(NIST_IV_GCM_E10);
+			*key_length = sizeof(NIST_KEY_GCM_E10);
+			break;
+		case 11:
+			*aad_length = sizeof(NIST_AAD_GCM_E11);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E11);
+			*t_length = sizeof(NIST_TAG_GCM_E11);
+			*iv_length = sizeof(NIST_IV_GCM_E11);
+			*key_length = sizeof(NIST_KEY_GCM_E11);
+			break;
+		case 12:
+			*aad_length = sizeof(NIST_AAD_GCM_E12);
+			*data_length = sizeof(NIST_TEST_DATA_GCM_E12);
+			*t_length = sizeof(NIST_TAG_GCM_E12);
+			*iv_length = sizeof(NIST_IV_GCM_E12);
+			*key_length = sizeof(NIST_KEY_GCM_E12);
+			break;
+	}
+
+}
+
+void load_test_data(unsigned char *aad, unsigned int aad_length,
+		    unsigned char *data, unsigned int data_length,
+		    unsigned char *result,
+		    unsigned char *t, unsigned int t_length,
+		    unsigned char *iv, unsigned int iv_length,
+		    unsigned char *key, unsigned int key_length,
+		    unsigned int iteration)
+{
+	switch (iteration) {
+		case 1:
+			memcpy(iv, NIST_IV_GCM_E1, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E1, aad_length);
+			memcpy(key, NIST_KEY_GCM_E1, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E1, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E1, data_length);
+			memcpy(t, NIST_TAG_GCM_E1, t_length);
+			break;
+		case 2:
+			memcpy(iv, NIST_IV_GCM_E2, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E2, aad_length);
+			memcpy(key, NIST_KEY_GCM_E2, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E2, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E2, data_length);
+			memcpy(t, NIST_TAG_GCM_E2, t_length);
+			break;
+		case 3:
+			memcpy(iv, NIST_IV_GCM_E3, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E3, aad_length);
+			memcpy(key, NIST_KEY_GCM_E3, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E3, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E3, data_length);
+			memcpy(t, NIST_TAG_GCM_E3, t_length);
+			break;
+		case 4:
+			memcpy(iv, NIST_IV_GCM_E4, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E4, aad_length);
+			memcpy(key, NIST_KEY_GCM_E4, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E4, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E4, data_length);
+			memcpy(t, NIST_TAG_GCM_E4, t_length);
+			break;
+		case 5:
+			memcpy(iv, NIST_IV_GCM_E5, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E5, aad_length);
+			memcpy(key, NIST_KEY_GCM_E5, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E5, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E5, data_length);
+			memcpy(t, NIST_TAG_GCM_E5, t_length);
+			break;
+		case 6:
+			memcpy(iv, NIST_IV_GCM_E6, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E6, aad_length);
+			memcpy(key, NIST_KEY_GCM_E6, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E6, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E6, data_length);
+			memcpy(t, NIST_TAG_GCM_E6, t_length);
+			break;
+		case 7:
+			memcpy(iv, NIST_IV_GCM_E7, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E7, aad_length);
+			memcpy(key, NIST_KEY_GCM_E7, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E7, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E7, data_length);
+			memcpy(t, NIST_TAG_GCM_E7, t_length);
+			break;
+		case 8:
+			memcpy(iv, NIST_IV_GCM_E8, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E8, aad_length);
+			memcpy(key, NIST_KEY_GCM_E8, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E8, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E8, data_length);
+			memcpy(t, NIST_TAG_GCM_E8, t_length);
+			break;
+		case 9:
+			memcpy(iv, NIST_IV_GCM_E9, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E9, aad_length);
+			memcpy(key, NIST_KEY_GCM_E9, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E9, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E9, data_length);
+			memcpy(t, NIST_TAG_GCM_E9, t_length);
+			break;
+		case 10:
+			memcpy(iv, NIST_IV_GCM_E10, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E10, aad_length);
+			memcpy(key, NIST_KEY_GCM_E10, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E10, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E10, data_length);
+			memcpy(t, NIST_TAG_GCM_E10, t_length);
+			break;
+		case 11:
+			memcpy(iv, NIST_IV_GCM_E11, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E11, aad_length);
+			memcpy(key, NIST_KEY_GCM_E11, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E11, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E11, data_length);
+			memcpy(t, NIST_TAG_GCM_E11, t_length);
+			break;
+		case 12:
+			memcpy(iv, NIST_IV_GCM_E12, iv_length);
+			memcpy(aad, NIST_AAD_GCM_E12, aad_length);
+			memcpy(key, NIST_KEY_GCM_E12, key_length);
+			memcpy(data, NIST_TEST_DATA_GCM_E12, data_length);
+			memcpy(result, NIST_TEST_RESULT_GCM_E12, data_length);
+			memcpy(t, NIST_TAG_GCM_E12, t_length);
+			break;
+	}
+
+}
+
+int test_gcm_kat(int iteration, int silent)
+{
+	unsigned int aad_length;
+	unsigned int data_length;
+	unsigned int t_length;
+	unsigned int iv_length;
+	unsigned int key_length;
+
+	get_sizes(&aad_length, &data_length, &t_length, &iv_length,
+		  &key_length, iteration);
+
+	printf("Test Parameters for iteration = %i\n", iteration);
+	printf("key length = %i, data length = %i, tag length = %i,"
+	       "iv length = %i aad_length = %i\n", key_length, data_length,
+	       t_length, iv_length, aad_length);
+
+	unsigned char iv[iv_length];
+	unsigned char input_data[data_length];
+	unsigned char encrypt[data_length];
+	unsigned char decrypt[data_length];
+	unsigned char result[data_length];
+	unsigned char aad[aad_length];
+	unsigned char key[key_length];
+	unsigned char t[t_length];
+	unsigned char t_result[t_length];
+
+	int rc = 0;
+
+	load_test_data(aad, aad_length, input_data, data_length, result,
+		       t_result, t_length, iv, iv_length, key, key_length,
+		       iteration);
+
+	rc = ica_aes_gcm(input_data, data_length,
+			 encrypt,
+			 iv, iv_length,
+			 aad, aad_length,
+			 t, t_length,
+			 key, key_length,
+			 1);
+	if (rc == EPERM) {
+		printf("ica_aes_gcm returns with EPERM (%d).\n", rc);
+		printf("Operation is not permitted on this machine. Test skipped!\n");
+		return 0;
+	}
+	if (rc) {
+		printf("ica_aes_gcm encrypt failed with rc = %i\n", rc);
+		dump_gcm_data(iv, iv_length, aad, aad_length, key, key_length,
+			      input_data, data_length, encrypt, t, t_length);
+	}
+	if (!silent && !rc) {
+		printf("Encrypt:\n");
+		dump_gcm_data(iv, iv_length, aad, aad_length, key, key_length,
+			      input_data, data_length, encrypt, t,
+			      t_length);
+	}
+
+	if (memcmp(result, encrypt, data_length)) {
+		printf("Encryption Result does not match the known ciphertext!\n");
+		printf("Expected data:\n");
+		dump_array(result, data_length);
+		printf("Encryption Result:\n");
+		dump_array(encrypt, data_length);
+		rc++;
+	}
+	if (memcmp(t, t_result, t_length)) {
+		printf("Tag result does not match the expected tag!\n");
+		printf("Expected tag:\n");
+		dump_array(t_result, t_length);
+		printf("Tag Result:\n");
+		dump_array(t, t_length);
+		rc++;
+	}
+	if (rc) {
+		printf("GCM test exited after encryption\n");
+		return rc;
+	}
+	rc = ica_aes_gcm(decrypt, data_length,
+			 encrypt,
+			 iv, iv_length,
+			 aad, aad_length,
+			 t, t_length,
+			 key, key_length,
+			 0);
+	if (rc == EPERM) {
+		printf("ica_aes_gcm returns with EPERM (%d).\n", rc);
+		printf("Operation is not permitted on this machine. Test skipped!\n");
+		return 0;
+	}
+	if (rc) {
+		printf("ica_aes_gcm decrypt failed with rc = %i\n", rc);
+		dump_gcm_data(iv, iv_length, aad, aad_length, key, key_length,
+			      encrypt, data_length, decrypt, t,
+			      t_length);
+	}
+
+
+	if (!silent && !rc) {
+		printf("Decrypt:\n");
+		dump_gcm_data(iv, iv_length, aad, aad_length, key, key_length,
+			      encrypt, data_length, decrypt, t,
+			      t_length);
+	}
+
+	if (memcmp(decrypt, input_data, data_length)) {
+		printf("Decryption Result does not match the original data!\n");
+		printf("Original data:\n");
+		dump_array(input_data, data_length);
+		printf("Decryption Result:\n");
+		dump_array(decrypt, data_length);
+		rc++;
+	}
+	if (memcmp(t, t_result, t_length)) {
+		printf("Tag result does not match the expected tag!\n");
+		printf("Expected tag:\n");
+		dump_array(t_result, t_length);
+		printf("Tag Result:\n");
+		dump_array(t, t_length);
+		rc++;
+	}
+	return rc;
+}
+
+int main(int argc, char **argv)
+{
+	// Default mode is 0. ECB,CBC and CFQ tests will be performed.
+	unsigned int silent = 0;
+	if (argc > 1) {
+		if (strstr(argv[1], "silent"))
+			silent = 1;
+		if (argc == 3)
+			if (strstr(argv[2], "silent"))
+				silent = 1;
+
+	}
+
+	int rc = 0;
+	int error_count = 0;
+	int iteration;
+	for(iteration = 1; iteration <= NR_TESTS; iteration++)	{
+		rc = test_gcm_kat(iteration, silent);
+		if (rc) {
+			printf("test_gcm_kat failed with rc = %i\n", rc);
+			error_count++;
+		} else
+			printf("test_gcm_kat finished successfuly\n");
+
+	}
+	if (error_count)
+		printf("%i of %i testcases failed\n", error_count, iteration);
+	else
+		printf("All testcases finished successfully.\n");
+	return rc;
+}
--- /dev/null
+++ b/src/tests/libica_cbccs_test.c
@@ -0,0 +1,563 @@
+/* This program is released under the Common Public License V1.0
+*
+* You should have received a copy of Common Public License V1.0 along with
+* with this program.
+*/
+
+/* (C) COPYRIGHT International Business Machines Corp. 2010  */
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "ica_api.h"
+#include <stdlib.h>
+#include <openssl/aes.h>
+
+/* CBC_CS data */
+unsigned char NIST_KEY[] = {
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
+};
+unsigned int key_size[6]  = { 24, 24, 24, 32, 32, 32 };
+unsigned char key[6][256] = {
+	{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20
+	},{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20
+	},{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20
+	},{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
+	},{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
+	},{
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
+	}
+};
+
+unsigned char key_512[] = {
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69,
+	0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+	0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
+};
+
+unsigned char NIST_IV[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+unsigned int NIST_TEST_DATA_LENGTH[6] = { 17, 31, 32, 47, 48, 64 };
+unsigned char NIST_TEST_DATA[6][100] = {
+	{ 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20
+	},{
+	0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+	0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+	0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20
+	},{
+	0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+	0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+	0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43
+	},{
+	0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+	0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+	0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+	0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+	0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c
+	},{
+	0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+	0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+	0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+	0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+	0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20
+	},{
+	0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+	0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+	0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+	0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+	0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+	0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20,
+	0x61, 0x6e, 0x64, 0x20, 0x77, 0x6f, 0x6e, 0x74,
+	0x6f, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x70, 0x2e
+	}
+};
+
+unsigned char NIST_TEST_RESULT[6][100] = {
+	{
+	0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
+	0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f, 0x97
+	},{
+	0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
+	0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
+	0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+	0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
+	},{
+	0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+	0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+	0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+	0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
+	},{
+	0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+	0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+	0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
+	0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
+	0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+	0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
+	},{
+	0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+	0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+	0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+	0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
+	0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+	0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
+	},{
+	0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+	0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+	0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+	0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+	0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
+	0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
+	0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+	0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
+	}
+};
+
+unsigned char NIST_NEXT_IV[6][16] = {
+	{
+	0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
+	0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f
+	},{
+	0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
+	0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22
+	},{
+	0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+	0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
+	},{
+	0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
+	0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e
+	},{
+	0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+	0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
+	},{
+	0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
+	0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40
+	}
+};
+
+
+void dump_array(char *ptr, int size)
+{
+	char *ptr_end;
+	unsigned char *h;
+	int i = 1;
+
+	h = (unsigned char *)ptr;
+	ptr_end = ptr + size;
+	while (h < (unsigned char *)ptr_end) {
+		printf("0x%02x ",(unsigned char ) *h);
+		h++;
+		if ((i == 16) & (h <(unsigned char *)ptr_end)) {
+			printf("\n");
+			i = 1;
+		} else {
+			++i;
+		}
+	}
+	printf("\n");
+}
+
+inline int compare_decrypt_result_with_expected_result(
+	unsigned char * decrypt_out,
+	unsigned char * expected_result,
+	unsigned int compare_length,
+	unsigned char * key,
+	unsigned int key_length,
+	unsigned char * iv,
+	unsigned int iv_size,
+	char * out_text,
+	unsigned int test_case_number)
+{
+	if (memcmp(decrypt_out, expected_result, compare_length) != 0) {
+		printf("This does NOT match the original data.\n");
+		printf("Test case number %i for %s with CBC_CS mode failed\n",
+		test_case_number, out_text) ;
+		printf("\nkey \n");
+		dump_array((char *) key, key_length);
+		printf("\nOriginal data:\n");
+		dump_array((char *) expected_result, compare_length);
+		printf("\ntmp iv\n");
+		dump_array((char *) iv, iv_size);
+		printf("\nExpected Result:\n");
+		dump_array((char *) expected_result, compare_length);
+		printf("\nDecrypted data:\n");
+		dump_array((char *) decrypt_out, compare_length);
+		return 1;
+	}
+	return 0;
+}
+
+
+int test_3des_new_api(unsigned int mode, unsigned int variant)
+{
+	/* Test 3des */
+	unsigned int iv_size = sizeof(ica_des_vector_t);
+	unsigned char iv[iv_size];
+	unsigned char tmp_iv[iv_size];
+	unsigned char enc_text[100] ,dec_text[100] ;
+	unsigned int number_of_testcases = 6;
+	int rc = 0, i = 0;
+
+	for (i = 0; i < number_of_testcases ; i++) {
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		rc = ica_3des_cbc_cs(NIST_TEST_DATA[i], enc_text,
+				     NIST_TEST_DATA_LENGTH[i], key[i],
+				     tmp_iv, 1, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], 8);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\ntest iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nica_3des_cbc_cs encrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		memset(dec_text,0,NIST_TEST_DATA_LENGTH[i]);
+		rc = ica_3des_cbc_cs(enc_text, dec_text,
+				     NIST_TEST_DATA_LENGTH[i], key[i],
+				     tmp_iv, 0, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], 8);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\noriginal iv\n");
+			dump_array((char *) &iv, iv_size);
+			printf("\ntmp iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nEncrypted data:\n");
+			dump_array((char *) enc_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nDecrypted data:\n");
+			dump_array((char *) dec_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nica_3des_cbc_cs decrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		if (compare_decrypt_result_with_expected_result(dec_text,
+				NIST_TEST_DATA[i], NIST_TEST_DATA_LENGTH[i],
+				key[i], 24, tmp_iv, iv_size,
+				(char *) "3DES", i))
+			return 1;
+		else
+			printf("Test case number %i for 3DES with CBC_CS mode was "
+			"successful!\n", i) ;
+	}
+	return rc;
+}
+int test_des_new_api(unsigned int mode, unsigned int variant)
+{
+	/* Test des */
+	unsigned int iv_size = sizeof(ica_des_vector_t);
+	unsigned char iv[iv_size];
+	unsigned char tmp_iv[iv_size];
+	unsigned char enc_text[100] ,dec_text[100] ;
+	unsigned int number_of_testcases = 6;
+	int rc = 0, i = 0;
+
+	for (i = 0; i < number_of_testcases ; i++) {
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		rc = ica_des_cbc_cs(NIST_TEST_DATA[i], enc_text,
+				    NIST_TEST_DATA_LENGTH[i], key[i],
+				    tmp_iv, 1, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], 8);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\ntest iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nica_des_cbc_cs encrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		memset(dec_text,0,NIST_TEST_DATA_LENGTH[i]);
+		rc = ica_des_cbc_cs(enc_text, dec_text,
+				    NIST_TEST_DATA_LENGTH[i], key[i],
+				    tmp_iv, 0, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], 8);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+			NIST_TEST_DATA_LENGTH[i]);
+			printf("\noriginal iv\n");
+			dump_array((char *) &iv, iv_size);
+			printf("\ntmp iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nEncrypted data:\n");
+			dump_array((char *) enc_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nDecrypted data:\n");
+			dump_array((char *) dec_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nica_des_cbc_cs decrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		if (compare_decrypt_result_with_expected_result(
+				dec_text, NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i], key[i],
+				(sizeof(key[i]) / 8), tmp_iv, iv_size,
+				(char *) "DES", i))
+			return 1;
+		else
+			printf("Test case number %i for DES with CBC_CS mode was "
+			"successful!\n", i);
+	}
+	return rc;
+}
+int test_aes_new_api(unsigned int mode, unsigned int variant)
+{
+	/* Test with 192 & 256 byte keys */
+	unsigned int iv_size = sizeof(ica_aes_vector_t);
+	unsigned char iv[iv_size];
+	unsigned char tmp_iv[iv_size];
+	char text[2][8] = {
+		{ 0x41, 0x45, 0x53, 0x2d, 0x31, 0x39, 0x32, 0x00 },
+		{ 0x41, 0x45, 0x53, 0x2d, 0x32, 0x35, 0x36, 0x00 }};
+	unsigned char enc_text[100] ,dec_text[100] ;
+	unsigned int number_of_testcases = 6;
+
+	int rc = 0, i = 0;
+
+	for (i = 0; i < number_of_testcases ; i++) {
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		rc = ica_aes_cbc_cs(NIST_TEST_DATA[i], enc_text,
+				    NIST_TEST_DATA_LENGTH[i], key[i],
+				    key_size[i], tmp_iv, 1, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], key_size[i]);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\ntest iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nica_aes_cbc_cs encrypt testcase %i failed with "
+				" errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		memset(dec_text,0,NIST_TEST_DATA_LENGTH[i]);
+		rc = ica_aes_cbc_cs(enc_text, dec_text,
+				    NIST_TEST_DATA_LENGTH[i], key[i],
+				    key_size[i], tmp_iv, 0, variant);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key[i], key_size[i]);
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\noriginal iv\n");
+			dump_array((char *) &iv, iv_size);
+			printf("\ntmp iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nEncrypted data:\n");
+			dump_array((char *) enc_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nDecrypted data:\n");
+			dump_array((char *) dec_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nica_aes_cbc_cs decrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+		if (compare_decrypt_result_with_expected_result(dec_text,
+				NIST_TEST_DATA[i], NIST_TEST_DATA_LENGTH[i],
+				key[i],	key_size[i], tmp_iv, iv_size,
+				(i < 3) ? text[0] : text[1], i))
+			return 1;
+		else
+			printf("Test case number %i for %s with CBC_CS mode was "
+			"successful!\n", i, (i < 3) ? text[0] : text[1]) ;
+	}
+	return rc;
+}
+
+int test_aes128_new_api(unsigned int mode)
+{
+	/* AES128 Known Answer Tests*/
+	unsigned int iv_size = sizeof(ica_aes_vector_t);
+	unsigned int key_size = AES_KEY_LEN128;
+	unsigned char iv[iv_size];
+	unsigned char tmp_iv[iv_size];
+	unsigned char key[key_size];
+	unsigned char enc_text[100] ,dec_text[100] ;
+	unsigned int number_of_testcases = 6;
+	int rc = 0, i = 0;
+
+	memcpy(key, NIST_KEY, sizeof(key));
+	for (i = 0; i < number_of_testcases ; i++) {
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		rc = ica_aes_cbc_cs(NIST_TEST_DATA[i], enc_text,
+				    NIST_TEST_DATA_LENGTH[i], key,
+				    sizeof(key), tmp_iv, 1, ICA_CBCCS_VARIANT3);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key, sizeof(key));
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\ntest iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nica_aes_cbc_cs encrypt testcase %i failed with "
+				"errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+
+		if (compare_decrypt_result_with_expected_result(enc_text,
+				NIST_TEST_RESULT[i], NIST_TEST_DATA_LENGTH[i],
+				key, sizeof(key), tmp_iv, iv_size,
+				(char *) "AES-128", i))
+			return 1;
+
+		if (compare_decrypt_result_with_expected_result(tmp_iv,
+				NIST_NEXT_IV[i], iv_size,
+				key, sizeof(key), tmp_iv, iv_size,
+				(char *) "AES-128", i))
+			return 1;
+
+		memcpy(tmp_iv, NIST_IV, iv_size);
+		memset(dec_text,0,NIST_TEST_DATA_LENGTH[i]);
+		rc = ica_aes_cbc_cs(enc_text, dec_text,
+				    NIST_TEST_DATA_LENGTH[i], key, sizeof(key),
+				    tmp_iv, 0, ICA_CBCCS_VARIANT3);
+		if (rc) {
+			printf("key \n");
+			dump_array((char *) key, sizeof(key));
+			printf("\nOriginal data:\n");
+			dump_array((char *) NIST_TEST_DATA[i],
+				NIST_TEST_DATA_LENGTH[i]);
+			printf("\noriginal iv\n");
+			dump_array((char *) &iv, iv_size);
+			printf("\ntmp iv\n");
+			dump_array((char *) tmp_iv, iv_size);
+			printf("\nkey\n");
+			dump_array((char *) key, sizeof(key));
+			printf("\nEncrypted data:\n");
+			dump_array((char *) enc_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nDecrypted data:\n");
+			dump_array((char *) dec_text, NIST_TEST_DATA_LENGTH[i]);
+			printf("\nica_aes_cbc_cs decrypt testcase %i failed"
+				"with errno %d (0x%x).\n", i, rc, rc);
+			return 1;
+		}
+
+		if (compare_decrypt_result_with_expected_result(dec_text,
+				NIST_TEST_DATA[i], NIST_TEST_DATA_LENGTH[i],
+				key, sizeof(key), tmp_iv, iv_size,
+				(char *) "AES-128", i))
+			return 1;
+		else
+			printf("Test case number %i for AES-128 with CBC_CS "
+			"mode was successful!\n", i) ;
+	}
+	return rc;
+}
+
+int main()
+{
+	unsigned int mode;
+	unsigned int variant;
+	int rc, error_count;
+
+	mode = MODE_CBCCS;
+	rc = 0;
+	error_count = 0;
+	printf("\n");
+
+	/* known answer tests for AES128 */
+	rc = test_aes128_new_api(mode);
+	if (rc) {
+		error_count++;
+		printf("test_aes128_new_api for CBC_CS mode with AES-128 "
+		"failed \n");
+		return rc;
+	}
+	else
+		printf("test_aes_new_api for CBC_CS mode with AES-128 "
+			"finished successfuly \n\n");
+
+	for (variant =  ICA_CBCCS_VARIANT1;
+	     variant <= ICA_CBCCS_VARIANT3;
+	     variant++) {
+		printf("\n--- Test cycle with CBCCS variant %d ---\n", variant);
+
+		/* AES 192 & 256 test */
+		rc = test_aes_new_api(mode, variant);
+		if (rc) {
+			error_count++;
+			printf("test_aes_new_api for CBC_CS mode with AES (192|256) "
+			       "failed \n");
+			return rc;
+		}
+		else {
+			printf("test_aes_new_api for CBC_CS mode with AES (192|256) "
+			       "finished successfuly \n\n");
+		}
+
+		/* DES tests */
+		rc = test_des_new_api(mode, variant);
+		if (rc) {
+			error_count++;
+			printf("test_des_new_api for CBC_CS mode with DES "
+			       "failed \n");
+			return rc;
+		} else {
+			printf("test_des_new_api for CBC_CS mode with DES "
+			       "finished successfuly \n\n");
+		}
+
+		/* 3DES tests */
+		rc = test_3des_new_api(mode, variant);
+		if (rc) {
+			error_count++;
+			printf("test_des_new_api for CBC_CS mode with 3DES "
+			       "failed \n");
+			return rc;
+		} else {
+			printf("test_des_new_api for CBC_CS mode with 3DES "
+			       "finished successfuly \n");
+		}
+	}
+
+	printf("\nAll CBC_CS mode tests finished successfuly\n\n");
+	return rc;
+}
+
--- /dev/null
+++ b/src/tests/libica_ccm_test.c
@@ -0,0 +1,203 @@
+/* This program is released under the Common Public License V1.0
+ *
+ * You should have received a copy of Common Public License V1.0 along with
+ * with this program.
+ */
+
+/* (C) COPYRIGHT International Business Machines Corp. 2011 */
+
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ica_api.h"
+
+#define BYTE 8
+
+#define NUM_CCM_TESTS 4
+unsigned char input_data[1000000];
+unsigned char parameter_block[32];
+unsigned char *to = parameter_block;
+
+unsigned int key_length[4] = {16, 16, 16, 16};
+unsigned char key[4][16] = {
+{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f },
+{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f },
+{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f },
+{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f }};
+
+#define CASE3_ASSOC_LEN 256
+/* Number of bytes in string for case 3 */
+
+unsigned int assoc_data_length[4] = {8, 16, 20, 65536};
+unsigned char assoc_data[4][65536] = {
+{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 },
+{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },
+{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+  0x10,0x11,0x12,0x13 }};
+unsigned int i = 0;
+unsigned char repeated_string[256] = {
+0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};
+unsigned int payload_length[4] = {4, 16, 24, 32};
+unsigned char payload[4][32] = {
+{ 0x20,0x21,0x22,0x23 },
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f},
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 },
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f ,
+  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f }};
+
+unsigned char payload_after_decrypt[4][32] = {
+{ 0x20,0x21,0x22,0x23 },
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f},
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 },
+{ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f ,
+  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f }};
+unsigned int nonce_length[4] = {7,8,12,13};
+unsigned char nonce[4][13] = {
+{ 0x10,0x11,0x12,0x13,0x14,0x15,0x16},
+{ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17},
+{ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b},
+{ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c}};
+
+unsigned int cbc_mac_length[4] = {4, 6, 8, 14};
+
+unsigned int cipher_text_length[4] = {8, 22, 32, 46};
+unsigned char cipher_text[4][46] = {
+{ 0x71,0x62,0x01,0x5b,0x4d,0xac,0x25,0x5d },
+{ 0xd2,0xa1,0xf0,0xe0,0x51,0xea,0x5f,0x62,0x08,0x1a,0x77,0x92,0x07,0x3d,0x59,0x3d,
+  0x1f,0xc6,0x4f,0xbf,0xac,0xcd },
+{ 0xe3,0xb2,0x01,0xa9,0xf5,0xb7,0x1a,0x7a,0x9b,0x1c,0xea,0xec,0xcd,0x97,0xe7,0x0b,
+  0x61,0x76,0xaa,0xd9,0xa4,0x42,0x8a,0xa5,0x48,0x43,0x92,0xfb,0xc1,0xb0,0x99,0x51},
+{0x69,0x91,0x5d,0xad,0x1e,0x84,0xc6,0x37,0x6a,0x68,0xc2,0x96,0x7e,0x4d,0xab,0x61,
+ 0x5a,0xe0,0xfd,0x1f,0xae,0xc4,0x4c,0xc4,0x84,0x82,0x85,0x29,0x46,0x3c,0xcf,0x72,
+ 0xb4,0xac,0x6b,0xec,0x93,0xe8,0x59,0x8e,0x7f,0x0d,0xad,0xbc,0xea,0x5b}
+};
+static void dump_array(unsigned char *ptr, unsigned int size)
+{
+	unsigned char *ptr_end;
+	unsigned char *h;
+	int i = 1, trunc = 0;
+	int maxsize = 2000;
+
+	puts("Dump:");
+
+	if (size > maxsize) {
+		trunc = size - maxsize;
+		size = maxsize;
+	}
+
+	h = ptr;
+	ptr_end = ptr + size;
+	while (h < ptr_end) {
+		printf("0x%02x ", *h);
+		h++;
+		if (i == 8) {
+			if (h != ptr_end)
+				printf("\n");
+		i = 1;
+		} else {
+			++i;
+		}
+	}
+	printf("\n");
+	if (trunc > 0)
+		printf("... %d bytes not printed\n", trunc);
+}
+
+int api_ccm_test(void)
+{
+	unsigned char *out_data;
+
+	printf("Test of CCM api\n");
+	while ( i < 65536 ) { // init big assoc_data
+		memcpy(assoc_data[3] + i, repeated_string, 256);
+		i= i + 256;
+	}
+	int rc = 0;
+	for (i = 0; i < NUM_CCM_TESTS; i++) {
+		printf("\nOriginal data for test %d:\n", i);
+		if (!(out_data = malloc(cipher_text_length[i])))
+                        return EINVAL;
+		memset(out_data, 0, cipher_text_length[i]);
+		rc = (ica_aes_ccm(payload[i], payload_length[i],
+				  out_data,
+				  cbc_mac_length[i],
+				  assoc_data[i], assoc_data_length[i],
+				  nonce[i], nonce_length[i],
+				  key[i], key_length[i],
+				  ICA_ENCRYPT));
+		if (rc) {
+			printf("icaccm encrypt failed with errno %d (0x%x).\n",
+				 rc, rc);
+			return rc;
+		}
+		printf("\nOutput Cipher text for test %d:\n", i);
+		dump_array(out_data, cipher_text_length[i]);
+		printf("\nExpected Cipher Text for test %d:\n", i);
+		dump_array(cipher_text[i], cipher_text_length[i]);
+		if (memcmp(cipher_text[i], out_data, cipher_text_length[i]) != 0) {
+			printf("This does NOT match the known result.\n");
+			return 1;
+		}
+		printf("Yep, that's how it should be encrypted.\n");
+		// start decrypt / verify
+		memset(payload[i], 0, payload_length[i]);
+		rc = (ica_aes_ccm(out_data, payload_length[i],
+				  cipher_text[i], cbc_mac_length[i],
+				  assoc_data[i], assoc_data_length[i],
+				  nonce[i], nonce_length[i],
+				  key[i], key_length[i],
+				  ICA_DECRYPT));
+		if (rc) {
+			printf("icaccm decrypt failed with errno %d (0x%x).\n",
+				rc,rc);
+			return rc;
+		}
+		printf("\nOutput payload for test %d:\n", i);
+		dump_array(out_data, payload_length[i]);
+		printf("\nExpected payload for test %d:\n", i);
+		dump_array(payload_after_decrypt[i], payload_length[i]);
+		if (memcmp(out_data, payload_after_decrypt[i],
+				payload_length[i]) == 0 ) {
+			printf("Yep, payload matches to original.\n");
+		} else {
+			printf("This does NOT match the known result.\n");
+			return 1;
+		}
+		free(out_data);
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int rc = 0;
+
+	rc = api_ccm_test();
+	if (rc) {
+		printf("api_ccm_test failed with rc = %i\n", rc);
+		return rc;
+	}
+	printf("api_ccm_test was succesful\n");
+	return 0;
+}
+
+
--- a/src/tests/libica_cmac_test.c
+++ b/src/tests/libica_cmac_test.c
@@ -218,6 +218,91 @@ int api_cmac_test(void)
 	return 0;
 }
 
+#define AES_BLOCK_SIZE 16
+
+inline unsigned int ica_aes_cmac_chaining(unsigned char *in,
+					  unsigned long in_length,
+					  unsigned char *cmac,
+					  unsigned int cmac_length,
+					  unsigned char *key,
+					  unsigned int key_length,
+					  unsigned int direction)
+{
+	unsigned char *last_block = NULL;
+	unsigned long tmp_length;
+	unsigned char tmp_iv[AES_BLOCK_SIZE];
+	unsigned int rc;
+
+	memset(tmp_iv, 0x00, AES_BLOCK_SIZE);
+
+	for (last_block = in, tmp_length = in_length;
+	     tmp_length > (AES_BLOCK_SIZE);
+	     last_block += AES_BLOCK_SIZE, tmp_length -= AES_BLOCK_SIZE) {
+		rc = ica_aes_cmac_intermediate(last_block, AES_BLOCK_SIZE,
+					       key, key_length,
+					       tmp_iv);
+		if (rc)
+			return rc;
+	}
+
+	return ica_aes_cmac_last(last_block, tmp_length,
+				 cmac, cmac_length,
+				 key, key_length,
+				 tmp_iv,
+				 direction);
+}
+
+int api_cmac_chaining_test(void)
+{
+	printf("Test of CMAC chaining api\n");
+	int rc = 0;
+	for (i = 0 ; i < NUM_TESTS; i++) {
+		if (!(cmac = malloc(cmac_length)))
+			return EINVAL;
+		memset(cmac, 0, cmac_length);
+		rc = ica_aes_cmac_chaining(message[i], mlen[i],
+					   cmac, cmac_length,
+					   key[i], key_length[i],
+					   ICA_ENCRYPT);
+		if (rc) {
+			printf("ica_aes_cmac chaining generate failed with errno %d (0x%x)."
+				"\n",rc,rc);
+			return rc;
+		}
+		if (memcmp(cmac, expected_cmac[i], cmac_length) != 0) {
+			printf("This does NOT match the known result. "
+				"Testcase %i failed\n",i);
+			printf("\nOutput MAC for test %d:\n", i);
+			dump_array((unsigned char *)cmac, cmac_length);
+			printf("\nExpected MAC for test %d:\n", i);
+			dump_array((unsigned char *)expected_cmac[i], 16);
+			free(cmac);
+			return 1;
+		}
+		printf("Expected MAC has been generated.\n");
+		rc = ica_aes_cmac_chaining(message[i], mlen[i],
+					   cmac, cmac_length,
+					   key[i], key_length[i],
+					   ICA_DECRYPT);
+		if (rc) {
+			printf("ica_aes_cmac verify failed with errno %d (0x%x).\n",
+				rc, rc);
+			free(cmac);
+			return rc;
+		}
+		free(cmac);
+		if (! rc )
+			printf("MAC was successful verified. testcase %i "
+				"succeeded\n",i);
+		else {
+			printf("MAC verification failed for testcase %i "
+				"with RC=%i\n",i,rc);
+			return rc;
+		}
+	}
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int rc = 0;
@@ -227,6 +312,13 @@ int main(int argc, char **argv)
 		printf("api_cmac_test failed with rc = %i\n", rc);
 		return rc;
 	}
+
+	rc = api_cmac_chaining_test();
+	if (rc) {
+		printf("api_cmac_test failed with rc = %i\n", rc);
+		return rc;
+	}
+
 	printf("api_cmac_test was succesful\n");
 	return 0;
 }
