only for backup, still in coding state - no compile!!!
[lcr.git] / crypt.cpp
diff --git a/crypt.cpp b/crypt.cpp
new file mode 100644 (file)
index 0000000..2babfb7
--- /dev/null
+++ b/crypt.cpp
@@ -0,0 +1,2046 @@
+/*****************************************************************************\
+**                                                                           **
+** PBX4Linux                                                                 **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** cryption stuff                                                            **
+**                                                                           **
+\*****************************************************************************/ 
+
+/* how authentication is performed:
+
+Alice                                                         Bob
+-----------------------------------------------------------------
+                         unencrypted call
+start        *
+            | -----> sending random number -----> (gets lost)
+             |
+             |                                     *        start
+comparing    | <----- sending random number <----- |
+master state |                                     |
+             | -----> sending "slave" code  -----> |  slave state
+calculating  |                                     |
+rsa key pair |                                     |
+             |                                     |
+done         | -----> sending public key    -----> |
+             |                                     |     crpyting
+             |                                     |  session key
+             |                                     |
+             | <----- sending session key   <----- |         done
+decrypting   |                                     | enable crypt
+dession key  |                                     *         stop
+             |
+done         |
+enable crypt |
+stop         *
+                         encrypted call
+
+When Bob and Alice activate their authentication process, they will make
+up a random number.
+
+Lets assume Alice starts encryption first. She activates the authentication
+process. Bob hat not activates the process yet. Alice sends a random number
+to Bob, but he will ignore it, because he is not listening.
+
+Bob also activates the authentication process, and sends his random number.
+Now Alice will receive that number and compares the values. If the values
+are equal, the process will fail and Alice will send the message "LOOPED".
+If Alice's random number is greater, she will identify herself as "master".
+Bob will get a "SLAVE" message. Bob might also send a "MASTER" message,
+if he got Alice's random number, due to parallel activation of the
+authentication.
+
+After transmission or reception of a master message, more messages are
+ignored. After reception of a "RANDOM" message, more messages are
+ignored. A reception of a "RANDOM" message always causes to identify who
+is slave.
+
+Now Alice starts calculating his public/private key pair, because she is
+"master". When Bob receives the "SLAVE" message, he will change the timeout
+value. If no random number or "SLAVE", "MASTER" or "LOOPED" is received within
+a timeout value, the "ABORT" message is sent. If the "ABORT" message is
+received at any state of the process, the process is aborted.
+
+After the key of Alices is calculated, she will send it to Bob. Bob will use
+the key to start encryption of a random session key. Both will change their
+timeout values.
+
+After Bob has finished is crypted session key, he will send it to Alice and
+enable encryption. Bob has finished his process now.
+
+As soon as Alice received the encrypted key, she will encrypt it and also
+enable encryption with the same key as Bob. Alis has finished her process now.
+
+Both will get displayed some of the first digits of the public key. Both can
+talk about the digits now. A man in the middle cannot change the keys without
+changing the public key. The voice of Alice and/or Bob is used to "sign" and
+"check" that the public key is not modified.
+
+If Alice or Bob wants to stop encryption, one will send the "ABORT" message.
+After transmission or reception.
+
+
+The states of the process:
+
+CM_ST_NULL
+----------
+no encryption
+
+CM_ST_IDENT
+-----------
+Waiting for the remote random number or "MASTER", "SLAVE", "LOOPED" message.
+
+CM_ST_KEYGEN
+------------
+The master generates the key and waits for the key engine to finish.
+
+CM_ST_KEYWAIT
+-------------
+The slave waits for the master to send the key.
+
+CM_ST_CSKEY
+-----------
+The slave generates the session key and waits for the encryption engine to
+finish.
+
+CM_ST_CSWAIT
+------------
+The master waits for the slave to send the crypted session key.
+
+CM_ST_DSKEY
+-----------
+The master waits for the decryption engine to finish decryption of the session
+key.
+
+CM_ST_ACTIVE
+------------
+The encryption is established.
+
+
+Timouts
+-------
+CM_TO_IDENT    = waiting for the remote party to enable encryption
+CM_TO_KEY      = waiting for key generation
+CM_TO_CSKEY    = waiting for session key encryption
+CM_TO_DSKEY    = waiting for session key decryption
+
+
+Structure of message:
+---------------------
+
+one octet message element
+two octets element length (first octet = high-byte)
+data as given in length
+
+last element is 0
+the message type is encoded as element
+
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef CRYPTO
+#include <openssl/rsa.h>
+#endif
+#include "main.h"
+
+
+/* convert key string to binary key vector
+ * returns 0 if an error ocurred
+ */
+unsigned char *crypt_key(unsigned char *key, int *binary_len)
+{
+       static unsigned char binary_key[2048];
+       int i = 0;
+
+       binary_key[0] = '\0';
+
+       if (!key[0])
+               return(NULL);
+
+       /* check for 0xXXXX... type of key */
+       if (!strncmp((char *)key, "0x", 2))
+       {
+               key+=2;
+               while(*key)
+               {
+                       if (i == (int)sizeof(binary_key))
+                               return(NULL);
+
+                       if (*key>='0' && *key<='9')
+                               binary_key[i] = (*key-'0') << 8;
+                       else if (*key>='a' && *key<='f')
+                               binary_key[i] = (*key-'a'+10) << 8;
+                       else if (*key>='A' && *key<='F')
+                               binary_key[i] = (*key-'A'+10) << 8;
+                       else
+                               return(NULL);
+                       key++;
+
+                       if (*key>='0' && *key<='9')
+                               binary_key[i] += (*key - '0');
+                       else if (*key>='a' && *key<='f')
+                               binary_key[i] += (*key - 'a' + 10);
+                       else if (*key>='A' && *key<='F')
+                               binary_key[i] += (*key - 'A' + 10);
+                       else
+                               return(NULL);
+                       key++;
+
+                       i++;
+               }
+               *binary_len = i;
+               return(binary_key);
+       }
+
+       /* ascii key too long */
+       if (strlen((char *)key) >= sizeof((char *)binary_key))
+               return(NULL);
+
+       memcpy(binary_key, key, strlen((char *)key));
+       *binary_len = strlen((char *)key);
+       return(binary_key);
+}
+
+/*
+ * support routine to get cpu speed
+ */
+static unsigned long get_bogomips(void)
+{
+       FILE *fp;
+       char buffer[64], *p;
+
+       fp = fopen("/proc/cpuinfo", "r");
+       if (!fp)
+       {
+               PERROR("Cannot access /proc/cpuinfo. Will not use cpuinfo for identification of pear\n");
+               return(0);
+       }
+       fduse++;
+       buffer[sizeof(buffer-1)] = '\0';
+       while(fgets(buffer, sizeof(buffer)-1, fp))
+       {
+               if (!!strncmp(buffer, "bogomips", 8))
+                       continue;
+               if (!strchr(buffer, ':'))
+                       continue;
+               p = strchr(buffer, ':')+1;
+               while(*p == ' ')
+                       p++;
+               if (strchr(p, '.'))
+                       *strchr(p, '.') = '\0';
+               fclose(fp);
+               fduse--;
+               return(atoi(p));
+       }
+       fclose(fp);
+       fduse--;
+       PERROR("Cannot find 'bogomips' in /proc/cpuinfo. Will not use cpuinfo for identification of pear\n");
+       return(0);
+}
+
+
+/*
+ * crc 32 stuff
+ */
+static unsigned long crc_reflect(unsigned long ref, char ch)
+{
+       unsigned long value = 0;
+       int i;
+
+       i = 1;
+       while(i < ch+1)
+       {
+               if(ref & 1)
+                       value |= 1 << (ch - i);
+               ref >>= 1;
+               i++;
+       }
+       return(value);
+}
+
+static unsigned long crc32_table[256];
+static int crc_initialized = 0;
+
+void crc_init(void)
+{
+       unsigned long ulPolynomial = 0x04c11db7;
+       int i, j;
+
+       i = 0;
+       while(i < 256)
+       {
+               crc32_table[i] = crc_reflect(i, 8) << 24;
+               j = 0;
+               while(j < 8)
+               {
+                       crc32_table[i] = (crc32_table[i] << 1) ^ (crc32_table[i] & (1 << 31) ? ulPolynomial : 0);
+                       j++;
+               }
+               crc32_table[i] = crc_reflect(crc32_table[i], 32);
+               i++;
+       }
+       crc_initialized = 1;
+}
+
+unsigned long crc32(unsigned char *data, int len)
+{
+       unsigned long crc = 0xffffffff;
+
+       if (!crc_initialized)
+       {
+               PERROR("crc not initialized, exitting...");
+               exit(-1);
+       }
+
+       while (len--)
+               crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data++];
+       return(crc^0xffffffff);
+}
+
+
+CM_ST_NAMES
+
+/* give name of state */
+static char *statename(int state)
+{
+       if (state>=0 && state<cm_st_num)
+               return(cm_st_name[state]);
+       return("<<STATE UNKNOWN>>");
+}
+
+/*
+ * authentication key generation, encryption, decryption
+ */
+struct auth_args {
+       class EndpointAppPBX *apppbx;
+       int     job;
+};
+
+static void *keyengine_child(void *arg)
+{
+       struct auth_args *args = (struct auth_args *)arg;
+       class EndpointAppPBX *apppbx = args->apppbx;
+       int job = args->job;
+#ifdef CRYPTO
+       RSA *rsa;
+       int exponent;
+       int i;
+#endif
+
+       struct sched_param schedp;
+       int ret;
+
+       PDEBUG((DEBUG_EPOINT | DEBUG_CRYPT), "EPOINT(%d) child process started for using libcrypto\n", apppbx->ea_endpoint->ep_serial);
+
+       /* lower priority to keep pbx running fluently */
+       if (options.schedule > 0)
+       {
+               memset(&schedp, 0, sizeof(schedp));
+               schedp.sched_priority = 0;
+               ret = sched_setscheduler(0, SCHED_OTHER, &schedp);
+               if (ret < 0)
+               {
+                       PERROR("Scheduling to normal priority failed (errno = %d).\nExitting child process...\n", errno);
+                       goto done;
+               }
+       }
+
+       switch(job)
+       {
+               /* generate rsa key pair */
+               case CK_GENRSA_REQ:
+#ifndef CRYPTO
+               PERROR("Not compliled wiht crypto.\n");
+               apppbx->e_crypt_keyengine_return = -1;
+#else
+               srandom(*((unsigned int *)mISDN_rand) ^ random());
+//             exponent = (((random()<<1)|1) & 0x7f) + 0x80; /* odd */
+               exponent = 65537;
+//             if (exponent < 3) exponent = 3; /* >= 3 */
+               rsa = RSA_generate_key(RSA_BITS, exponent, NULL, NULL);
+               if (!rsa)
+               {
+                       PERROR("Failed to generate rsa key pair.\n");
+                       apppbx->e_crypt_keyengine_return = -1;
+                       break;
+               }
+               ememuse++;
+               apppbx->e_crypt_rsa_n_len = BN_num_bytes(rsa->n);
+               if (apppbx->e_crypt_rsa_n_len > (int)sizeof(apppbx->e_crypt_rsa_n))
+               {
+                       kerror_buffer:
+                       PERROR("e_crypt_rsa_* too small for bignum.\n");
+                       apppbx->e_crypt_keyengine_return = -1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               BN_bn2bin(rsa->n, apppbx->e_crypt_rsa_n);
+               apppbx->e_crypt_rsa_n_len = BN_num_bytes(rsa->n);
+               if (apppbx->e_crypt_rsa_e_len > (int)sizeof(apppbx->e_crypt_rsa_e))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->e, apppbx->e_crypt_rsa_e);
+               apppbx->e_crypt_rsa_e_len = BN_num_bytes(rsa->e);
+               if (apppbx->e_crypt_rsa_d_len > (int)sizeof(apppbx->e_crypt_rsa_d))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->d, apppbx->e_crypt_rsa_d);
+               apppbx->e_crypt_rsa_p_len = BN_num_bytes(rsa->p);
+               if (apppbx->e_crypt_rsa_p_len > (int)sizeof(apppbx->e_crypt_rsa_p))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->p, apppbx->e_crypt_rsa_p);
+               apppbx->e_crypt_rsa_q_len = BN_num_bytes(rsa->q);
+               if (apppbx->e_crypt_rsa_q_len > (int)sizeof(apppbx->e_crypt_rsa_q))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->q, apppbx->e_crypt_rsa_q);
+               apppbx->e_crypt_rsa_dmp1_len = BN_num_bytes(rsa->dmp1);
+               if (apppbx->e_crypt_rsa_dmp1_len > (int)sizeof(apppbx->e_crypt_rsa_dmp1))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->dmp1, apppbx->e_crypt_rsa_dmp1);
+               apppbx->e_crypt_rsa_dmq1_len = BN_num_bytes(rsa->dmq1);
+               if (apppbx->e_crypt_rsa_dmq1_len > (int)sizeof(apppbx->e_crypt_rsa_dmq1))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->dmq1, apppbx->e_crypt_rsa_dmq1);
+               apppbx->e_crypt_rsa_iqmp_len = BN_num_bytes(rsa->iqmp);
+               if (apppbx->e_crypt_rsa_iqmp_len > (int)sizeof(apppbx->e_crypt_rsa_iqmp))
+                       goto kerror_buffer;
+               BN_bn2bin(rsa->iqmp, apppbx->e_crypt_rsa_iqmp);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa n=%02x...\n", *apppbx->e_crypt_rsa_n);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa e=%02x...\n", *apppbx->e_crypt_rsa_e);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa d=%02x...\n", *apppbx->e_crypt_rsa_d);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa p=%02x...\n", *apppbx->e_crypt_rsa_p);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa q=%02x...\n", *apppbx->e_crypt_rsa_q);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa dmp1=%02x...\n", *apppbx->e_crypt_rsa_dmp1);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa dmq1=%02x...\n", *apppbx->e_crypt_rsa_dmq1);
+               PDEBUG(DEBUG_CRYPT, "gen: rsa iqmp=%02x...\n", *apppbx->e_crypt_rsa_iqmp);
+               apppbx->e_crypt_keyengine_return = 1;
+               RSA_free(rsa);
+               ememuse--;
+#endif
+               break;
+
+               /* encrypt session key */
+               case CK_CPTRSA_REQ:
+#ifndef CRYPTO
+               PERROR("No crypto lib.\n");
+               apppbx->e_crypt_keyengine_return = -1;
+#else
+               /* generating session key */
+               srandom(*((unsigned int *)mISDN_rand) ^ random());
+               i = 0;
+               while(i < 56)
+               {
+                       apppbx->e_crypt_key[i] = random();
+                       apppbx->e_crypt_key[i] ^= mISDN_rand[random() & 0xff];
+                       i++;
+               }
+               apppbx->e_crypt_key_len = i;
+               /* encrypt via rsa */
+               rsa = RSA_new();
+               if (!rsa)
+               {
+                       PERROR("Failed to allocate rsa structure.\n");
+                       apppbx->e_crypt_keyengine_return = 1;
+                       break;
+               }
+               ememuse++;
+               rsa->n = BN_new();
+               rsa->e = BN_new();
+               if (!rsa->n || !rsa->e)
+               {
+                       PERROR("Failed to generate rsa structure.\n");
+                       apppbx->e_crypt_keyengine_return = -1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_n, apppbx->e_crypt_rsa_n_len, rsa->n))
+               {
+                       eerror_bin2bn:
+                       PERROR("Failed to convert binary to bignum.\n");
+                       apppbx->e_crypt_keyengine_return = -1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               if ((apppbx->e_crypt_rsa_n_len*8) != BN_num_bits(rsa->n))
+               {
+                       PERROR("SOFTWARE API ERROR: length not equal stored data. (%d != %d)\n", apppbx->e_crypt_rsa_n_len*8, BN_num_bits(rsa->n));
+                       apppbx->e_crypt_keyengine_return = -1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_e, apppbx->e_crypt_rsa_e_len, rsa->e))
+                       goto eerror_bin2bn;
+               PDEBUG(DEBUG_CRYPT, "crypt: rsa n=%02x...\n", *apppbx->e_crypt_rsa_n);
+               PDEBUG(DEBUG_CRYPT, "crypt: rsa e=%02x...\n", *apppbx->e_crypt_rsa_e);
+               PDEBUG(DEBUG_CRYPT, "crypt: key =%02x%02x%02x%02x... (len=%d)\n", apppbx->e_crypt_key[0], apppbx->e_crypt_key[1], apppbx->e_crypt_key[2], apppbx->e_crypt_key[3], apppbx->e_crypt_key_len);
+               apppbx->e_crypt_ckey_len = RSA_public_encrypt(
+                       apppbx->e_crypt_key_len,
+                       apppbx->e_crypt_key,
+                       apppbx->e_crypt_ckey,
+                       rsa,
+                       RSA_PKCS1_PADDING);
+               PDEBUG(DEBUG_CRYPT, "crypt: ckey =%02x%02x%02x%02x... (len=%d)\n", apppbx->e_crypt_ckey[0], apppbx->e_crypt_ckey[1], apppbx->e_crypt_ckey[2], apppbx->e_crypt_ckey[3], apppbx->e_crypt_ckey_len);
+               RSA_free(rsa);
+               ememuse--;
+               if (apppbx->e_crypt_ckey_len > 0)
+                       apppbx->e_crypt_keyengine_return = 1;
+               else
+                       apppbx->e_crypt_keyengine_return = -1;
+#endif
+               break;
+
+               /* decrypt session key */
+               case CK_DECRSA_REQ:
+#ifndef CRYPTO
+               PERROR("No crypto lib.\n");
+               apppbx->e_crypt_keyengine_return = -1;
+#else
+               rsa = RSA_new();
+               if (!rsa)
+               {
+                       PERROR("Failed to allocate rsa structure.\n");
+                       apppbx->e_crypt_keyengine_return = 1;
+                       break;
+               }
+               ememuse++;
+               rsa->n = BN_new();
+               rsa->e = BN_new();
+               rsa->d = BN_new();
+               rsa->p = BN_new();
+               rsa->q = BN_new();
+               rsa->dmp1 = BN_new();
+               rsa->dmq1 = BN_new();
+               rsa->iqmp = BN_new();
+               if (!rsa->n || !rsa->e
+                || !rsa->d || !rsa->p
+                || !rsa->q || !rsa->dmp1
+                || !rsa->dmq1 || !rsa->iqmp)
+               {
+                       PERROR("Failed to generate rsa structure.\n");
+                       apppbx->e_crypt_keyengine_return = 1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_n, apppbx->e_crypt_rsa_n_len, rsa->n))
+               {
+                       derror_bin2bn:
+                       PERROR("Failed to convert binary to bignum.\n");
+                       apppbx->e_crypt_keyengine_return = -1;
+                       RSA_free(rsa);
+                       ememuse--;
+                       break;
+               }
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_e, apppbx->e_crypt_rsa_e_len, rsa->e))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_d, apppbx->e_crypt_rsa_d_len, rsa->d))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_p, apppbx->e_crypt_rsa_p_len, rsa->p))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_q, apppbx->e_crypt_rsa_q_len, rsa->q))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_dmp1, apppbx->e_crypt_rsa_dmp1_len, rsa->dmp1))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_dmq1, apppbx->e_crypt_rsa_dmq1_len, rsa->dmq1))
+                       goto derror_bin2bn;
+               if (!BN_bin2bn(apppbx->e_crypt_rsa_iqmp, apppbx->e_crypt_rsa_iqmp_len, rsa->iqmp))
+                       goto derror_bin2bn;
+               PDEBUG(DEBUG_CRYPT, "decrypt: ckey =%02x%02x%02x%02x... (len=%d)\n", apppbx->e_crypt_ckey[0], apppbx->e_crypt_ckey[1], apppbx->e_crypt_ckey[2], apppbx->e_crypt_ckey[3], apppbx->e_crypt_ckey_len);
+               apppbx->e_crypt_key_len = RSA_private_decrypt(
+                       apppbx->e_crypt_ckey_len,
+                       apppbx->e_crypt_ckey,
+                       apppbx->e_crypt_key,
+                       rsa,
+                       RSA_PKCS1_PADDING);
+               PDEBUG(DEBUG_CRYPT, "decrypt: key =%02x%02x%02x%02x... (len=%d)\n", apppbx->e_crypt_key[0], apppbx->e_crypt_key[1], apppbx->e_crypt_key[2], apppbx->e_crypt_key[3], apppbx->e_crypt_key_len);
+               RSA_free(rsa);
+               ememuse--;
+               apppbx->e_crypt_keyengine_return = 1;
+#endif
+               break;
+
+               default:
+               PERROR("Unknown job %d\n", job);
+               apppbx->e_crypt_keyengine_return = -1;
+       }
+
+       done:
+       PDEBUG((DEBUG_EPOINT | DEBUG_CRYPT), "child process done after using libcrypto with return value %d\n", apppbx->e_crypt_keyengine_return);
+
+       /* exit process */
+       apppbx->ea_endpoint->ep_use--;
+       memset(args, 0, sizeof(struct auth_args));
+       free(args);
+       amemuse--;
+       return(NULL);
+}
+
+void EndpointAppPBX::cryptman_keyengine(int job)
+{
+       struct auth_args *arg;
+       pthread_t tid;
+
+       if (e_crypt_keyengine_busy)
+       {
+               e_crypt_keyengine_return = -1;
+               PERROR("engine currently busy.\n");
+               return;
+       }
+
+       arg = (struct auth_args *)calloc(1, sizeof(struct auth_args));
+       if (!arg)
+       {
+               PERROR("failed to alloc memory.\n");
+               e_crypt_keyengine_return = -1;
+               return;
+       }
+
+       arg->apppbx = this;
+       arg->job = job;
+       e_crypt_keyengine_return = 0;
+       e_crypt_keyengine_busy = job;
+
+       ea_endpoint->ep_use++;
+       if ((pthread_create(&tid, NULL, keyengine_child, arg)<0))
+       {
+               ea_endpoint->ep_use--;
+               PERROR("failed to create keyengine-thread.\n");
+               e_crypt_keyengine_return = -1;
+               return;
+       }
+       amemuse++;
+
+       PDEBUG((DEBUG_EPOINT | DEBUG_CRYPT), "send_mail(%d): child process created for doing crypto stuff\n", ea_endpoint->ep_serial);
+
+}
+
+
+/* handler for authentication (called by apppbx's handler)
+ */
+void EndpointAppPBX::cryptman_handler(void)
+{
+       if (e_crypt_keyengine_busy)
+       {
+               if (e_crypt_keyengine_return < 0)
+               {
+                       e_crypt_keyengine_busy = 0;
+                       cryptman_message(CK_ERROR_IND, NULL, 0);
+               } else
+               if (e_crypt_keyengine_return > 0)
+               {
+                       switch(e_crypt_keyengine_busy)
+                       {
+                               case CK_GENRSA_REQ:
+                               e_crypt_keyengine_busy = 0;
+                               cryptman_message(CK_GENRSA_CONF, NULL, 0);
+                               break;
+                               case CK_CPTRSA_REQ:
+                               e_crypt_keyengine_busy = 0;
+                               cryptman_message(CK_CPTRSA_CONF, NULL, 0);
+                               break;
+                               case CK_DECRSA_REQ:
+                               e_crypt_keyengine_busy = 0;
+                               cryptman_message(CK_DECRSA_CONF, NULL, 0);
+                               break;
+                       }
+               }
+       }
+
+       /* check for event, make next event */
+       if (e_crypt_timeout_sec) if (e_crypt_timeout_sec<now_tv.tv_sec || (e_crypt_timeout_sec==now_tv.tv_sec && e_crypt_timeout_usec<now_tv.tv_usec))
+       {
+               e_crypt_timeout_sec = 0;
+               e_crypt_timeout_usec = 0;
+               cryptman_message(CT_TIMEOUT, NULL, 0);
+       }
+}
+
+
+/*
+ * process message to the crypt manager
+ */
+/* remote peer sends ident request */
+void EndpointAppPBX::cr_ident(int message, unsigned char *param, int len)
+{
+       unsigned char buf[4], *p;
+       unsigned long bogomips = 0, ran;
+       int l;
+
+       l = CM_SIZEOFINF(CM_INFO_RANDOM);
+       if (l != 4)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) missing (or corrupt) random number, ignoring (len = %d)\n", ea_endpoint->ep_serial, l);
+               return;
+       }
+       p = CM_GETINF(CM_INFO_RANDOM, buf);
+       ran = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
+       l = CM_SIZEOFINF(CM_INFO_BOGOMIPS);
+       if (l != 4)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) missing (or corrupt) random bogomips, just comparing random (len = %d)\n", ea_endpoint->ep_serial, l);
+               goto compare_random;
+       }
+       p = CM_GETINF(CM_INFO_BOGOMIPS, buf);
+       bogomips = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
+       if (e_crypt_bogomips > bogomips)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) our cpu is faster, so we are master (%d > %d)\n", ea_endpoint->ep_serial, e_crypt_bogomips, bogomips);
+               cr_master(message, NULL, 0);
+               return;
+       }
+       if (e_crypt_bogomips < bogomips)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) our cpu is slower, so we are slave (%d < %d)\n", ea_endpoint->ep_serial, e_crypt_bogomips, bogomips);
+               cr_slave(message, NULL, 0);
+               return;
+       }
+       PDEBUG(DEBUG_CRYPT, "EPOINT(%d) our cpu is equal speed, so we check for random value (%d == %d)\n", ea_endpoint->ep_serial, e_crypt_bogomips, bogomips);
+       compare_random:
+       /* bogomips are equal, so we compare */
+       if (e_crypt_random > ran)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) our random value is greater, so we are master (%d > %d)\n", ea_endpoint->ep_serial, e_crypt_random, ran);
+               cr_master(message, NULL, 0);
+               return;
+       }
+       if (e_crypt_random < ran)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) our random value is smaller, so we are slave (%d < %d)\n", ea_endpoint->ep_serial, e_crypt_random, ran);
+               cr_slave(message, NULL, 0);
+               return;
+       }
+       PDEBUG(DEBUG_CRYPT, "EPOINT(%d) random values are equal, so we are looped (%d == %d)\n", ea_endpoint->ep_serial, e_crypt_random, ran);
+       cr_looped(message, NULL, 0);
+}
+
+/* key-exchange activation by the user */
+void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+       unsigned char bogomips[4], ran[4];
+
+       /* activate listener */
+       cryptman_msg2crengine(CR_LISTEN_REQ, NULL, 0);
+       /* send ident message */
+       msg = CMSG_IDENT;
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       /* random number element */
+       srandom(now_tv.tv_sec ^ now_tv.tv_usec ^ random());
+       e_crypt_random = random();
+       ran[0] = e_crypt_random >> 24;
+       ran[1] = e_crypt_random >> 16;
+       ran[2] = e_crypt_random >> 8;
+       ran[3] = e_crypt_random;
+       CM_ADDINF(CM_INFO_RANDOM, 4, ran);
+       /* cpu speed element */
+       e_crypt_bogomips = get_bogomips();
+       if (e_crypt_bogomips > 0)
+       {
+               bogomips[0] = e_crypt_bogomips >> 24;
+               bogomips[1] = e_crypt_bogomips >> 16;
+               bogomips[2] = e_crypt_bogomips >> 8;
+               bogomips[3] = e_crypt_bogomips;
+               CM_ADDINF(CM_INFO_BOGOMIPS, 4, bogomips);
+       }
+       /* send ident message */
+       cryptman_msg2peer(buf);
+       /* change state */
+       cryptman_state(CM_ST_IDENT);
+       /* set timeout */
+       cryptman_timeout(CM_TO_IDENT);
+}
+
+/* deactivation by the user */
+void EndpointAppPBX::cr_deactivate(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+
+       /* deactivate listener (if not already) */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* message */
+       msg = CMSG_ABORT;
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       cryptman_msg2peer(buf);
+       /* deactivate encryption */
+       cryptman_msg2crengine(CC_DACT_REQ, NULL, 0);
+       /* change state */
+       cryptman_state(CM_ST_NULL);
+       /* send message to user */
+       cryptman_msg2user(CU_DACT_CONF, "Deactivated");
+}
+
+/* remote peer tells us to be master */
+void EndpointAppPBX::cr_master(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+
+       /* change to master state */
+       cryptman_state(CM_ST_KEYGEN);
+       if (message == CP_IDENT)
+       {
+               /* send you-are-slave-message */
+               msg = CMSG_SLAVE;
+               CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+               cryptman_msg2peer(buf);
+       }
+       /* start generation of key */
+       cryptman_keyengine(CK_GENRSA_REQ);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to user */
+       cryptman_msg2user(CU_INFO_IND, "Master");
+}
+
+/* remote peer tells us to be slave */
+void EndpointAppPBX::cr_slave(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+
+       /* change to slave state */
+       cryptman_state(CM_ST_KEYWAIT);
+       if (message == CP_IDENT)
+       {
+               /* send you-are-slave-message */
+               msg = CMSG_MASTER;
+               /* message */
+               CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+               cryptman_msg2peer(buf);
+       }
+       /* set timeout */
+       cryptman_timeout(CM_TO_PUBKEY);
+       /* send message to user */
+       cryptman_msg2user(CU_INFO_IND, "Slave");
+}
+
+/* remote peer tells us about loop */
+void EndpointAppPBX::cr_looped(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       if (message == CP_IDENT)
+       {
+               /* send looped */
+               msg = CMSG_LOOPED;
+               /* message */
+               CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+               cryptman_msg2peer(buf);
+       }
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to user */
+       cryptman_msg2user(CU_ERROR_IND, "Loop Detected");
+}
+
+/* abort */
+void EndpointAppPBX::cr_abort(int message, unsigned char *param, int len)
+{
+       /* if already encrypting */
+       if (e_crypt_state==CM_ST_WAIT_CRYPT
+        || e_crypt_state==CM_ST_SWAIT
+        || e_crypt_state==CM_ST_ACTIVE)
+       {
+               /* deactivate blowfish */
+               cryptman_msg2crengine(CC_DACT_REQ, NULL, 0);
+       }
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to user */
+       if (message == CT_TIMEOUT)
+               cryptman_msg2user(CU_ERROR_IND, "Timeout");
+       else if (message == CP_ABORT)
+               cryptman_msg2user(CU_ERROR_IND, "Remote Abort");
+       else
+               cryptman_msg2user(CU_DACT_IND, NULL);
+}
+
+/* abort but wait for engine to release*/
+void EndpointAppPBX::cr_abort_engine(int message, unsigned char *param, int len)
+{
+       /* change to release state */
+       cryptman_state(CM_ST_RELEASE);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to user */
+       if (message == CT_TIMEOUT)
+               cryptman_msg2user(CU_ERROR_IND, "Timeout");
+       else if (message == CP_ABORT)
+               cryptman_msg2user(CU_ERROR_IND, "Remote Abort");
+       else
+               cryptman_msg2user(CU_DACT_IND, NULL);
+}
+
+/* abort and disable crypt engine */
+void EndpointAppPBX::cr_abort_wait(int message, unsigned char *param, int len)
+{
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* deactivate listener (if not already) */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* deactivate blowfish */
+       cryptman_msg2crengine(CC_DACT_REQ, NULL, 0);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to user */
+       if (message == CT_TIMEOUT)
+               cryptman_msg2user(CU_ERROR_IND, "Timeout");
+       else if (message == CP_ABORT)
+               cryptman_msg2user(CU_ERROR_IND, "Remote Abort");
+       else
+               cryptman_msg2user(CU_DACT_IND, NULL);
+}
+
+/* key engine tells us that the rsa is ready */
+void EndpointAppPBX::cr_genrsa(int message, unsigned char *param, int len)
+{
+       unsigned char buf[1024] = "";
+       unsigned char msg;
+
+       /* change to wait for crypted session key state */
+       cryptman_state(CM_ST_CSWAIT);
+       /* message */
+       msg = CMSG_PUBKEY;
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       CM_ADDINF(CM_INFO_PUBKEY, e_crypt_rsa_n_len, &e_crypt_rsa_n);
+       CM_ADDINF(CM_INFO_PUBEXPONENT, e_crypt_rsa_e_len, &e_crypt_rsa_e);
+       cryptman_msg2peer(buf);
+       /* set timeout */
+       cryptman_timeout(CM_TO_CSKEY);
+}
+
+/* our engine has a key error */
+void EndpointAppPBX::cr_keyerror(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg;
+
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* message */
+       msg = CMSG_ABORT;
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       cryptman_msg2peer(buf);
+       /* send message to user */
+       cryptman_msg2user(CU_ERROR_IND, "Local Key Error");
+}
+
+/* remote sends us the rsa public key */
+void EndpointAppPBX::cr_pubkey(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg = CMSG_ABORT;
+       int l;
+
+       l = CM_SIZEOFINF(CM_INFO_PUBKEY);
+       if (l<1 || l>(int)sizeof(e_crypt_rsa_n))
+       {
+               size_error:
+               /* change to idle state */
+               cryptman_state(CM_ST_NULL);
+               /* deactivate listener */
+               cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+               /* message */
+               CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+               cryptman_msg2peer(buf);
+               /* send message to user */
+               cryptman_msg2user(CU_ERROR_IND, "Remote Key Error");
+               return;
+       }
+       CM_GETINF(CM_INFO_PUBKEY, e_crypt_rsa_n);
+       e_crypt_rsa_n_len = l;
+       l = CM_SIZEOFINF(CM_INFO_PUBEXPONENT);
+       if (l<1 || l>(int)sizeof(e_crypt_rsa_e))
+               goto size_error;
+       CM_GETINF(CM_INFO_PUBEXPONENT, e_crypt_rsa_e);
+       e_crypt_rsa_e_len = l;
+       /* change to generating encrypted sessnion key state */
+       cryptman_state(CM_ST_CSKEY);
+       /* start generation of crypted session key */
+       cryptman_keyengine(CK_CPTRSA_REQ);
+       /* disable timeout */
+       cryptman_timeout(0);
+}
+
+/* key engine tells us that the crypted session key is ready */
+void EndpointAppPBX::cr_cptrsa(int message, unsigned char *param, int len)
+{
+       unsigned char buf[1024] = "";
+       unsigned char msg = CMSG_CSKEY;
+
+       /* change to wait for crypt engine state */
+       cryptman_state(CM_ST_WAIT_DELAY);
+       /* message */
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       CM_ADDINF(CM_INFO_CSKEY, e_crypt_ckey_len, &e_crypt_ckey);
+       cryptman_msg2peer(buf);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* timeout 1 sec */
+       cryptman_timeout(1);
+}
+
+/* now we waited for the remote to receive and decrypt the session key */
+void EndpointAppPBX::cr_waitdelay(int message, unsigned char *param, int len)
+{
+       /* change to wait for crypt engine state */
+       cryptman_state(CM_ST_WAIT_CRYPT);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send message to crypt engine */
+       cryptman_msg2crengine(CC_ACTBF_REQ, e_crypt_key, e_crypt_key_len);
+}
+
+/* remote sends us the crypted session key */
+void EndpointAppPBX::cr_cskey(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg = CMSG_ABORT;
+       int l;
+
+       /* disable timeout */
+       cryptman_timeout(0);
+       l = CM_SIZEOFINF(CM_INFO_CSKEY);
+       if (l<1 || l>(int)sizeof(e_crypt_ckey))
+       {
+               /* change to idle state */
+               cryptman_state(CM_ST_NULL);
+               /* deactivate listener */
+               cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+               /* message */
+               CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+               cryptman_msg2peer(buf);
+               /* send message to user */
+               cryptman_msg2user(CU_ERROR_IND, "Remote Key Error");
+               return;
+       }
+       CM_GETINF(CM_INFO_CSKEY, e_crypt_ckey);
+       e_crypt_ckey_len = l;
+       /* change to generating decrypted session key state */
+       cryptman_state(CM_ST_SESSION);
+       /* start generation of decrypted session key */
+       cryptman_keyengine(CK_DECRSA_REQ);
+}
+
+/* key engine tells us that the decrypted session key is ready */
+void EndpointAppPBX::cr_decrsa(int message, unsigned char *param, int len)
+{
+       /* change to wait for crypt engine state */
+       cryptman_state(CM_ST_WAIT_CRYPT);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* send message to crypt engine */
+       cryptman_msg2crengine(CC_ACTBF_REQ, e_crypt_key, e_crypt_key_len);
+}
+
+/* blowfish now active */
+void EndpointAppPBX::cr_bfactive(int message, unsigned char *param, int len)
+{
+       char text[64];
+
+       /* change to active state */
+       cryptman_state(CM_ST_ACTIVE);
+       /* send message to user */
+       SPRINT(text, "PUB %02x%02x %02x%02x %02x%02x %02x%02x", e_crypt_key[0], e_crypt_key[1], e_crypt_key[2], e_crypt_key[3], e_crypt_key[4], e_crypt_key[5], e_crypt_key[6], e_crypt_key[7]);
+       cryptman_msg2user(CU_ACTK_CONF, text);
+}
+
+/* our crypt engine sends an error */
+void EndpointAppPBX::cr_crypterror(int message, unsigned char *param, int len)
+{
+       unsigned char buf[128] = "";
+       unsigned char msg = CMSG_ABORT;
+
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* deactivate listener */
+       cryptman_msg2crengine(CR_UNLISTEN_REQ, NULL, 0);
+       /* message */
+       CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
+       cryptman_msg2peer(buf);
+       /* send message to user */
+       cryptman_msg2user(CU_ERROR_IND, "Blowfish Error");
+}
+
+/* engine is done, now we are done with release */
+void EndpointAppPBX::cr_release(int message, unsigned char *param, int len)
+{
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+}
+
+/* activate using shared key */
+void EndpointAppPBX::cr_sactivate(int message, unsigned char *param, int len)
+{
+       /* change to 'wait for crypt engine' state */
+       cryptman_state(CM_ST_SWAIT);
+       /* disable timeout */
+       cryptman_timeout(0);
+       /* send key to crypt engine */
+       cryptman_msg2crengine(CC_ACTBF_REQ, param, len);
+}
+
+/* share key deactivation by the user */
+void EndpointAppPBX::cr_sdeactivate(int message, unsigned char *param, int len)
+{
+       /* deactivate encryption */
+       cryptman_msg2crengine(CC_DACT_REQ, NULL, 0);
+       /* change state */
+       cryptman_state(CM_ST_NULL);
+       /* send message to user */
+       cryptman_msg2user(CU_DACT_CONF, NULL);
+}
+
+/* shared key abort */
+void EndpointAppPBX::cr_sabort(int message, unsigned char *param, int len)
+{
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* send message to user */
+       cryptman_msg2user(CU_DACT_IND, "Deactivated");
+}
+
+/* shared key: our crypt engine sends an error */
+void EndpointAppPBX::cr_scrypterror(int message, unsigned char *param, int len)
+{
+       /* change to idle state */
+       cryptman_state(CM_ST_NULL);
+       /* send message to user */
+       cryptman_msg2user(CU_ERROR_IND, "Blowfish Error");
+}
+
+/* blowfish now active */
+void EndpointAppPBX::cr_sbfactive(int message, unsigned char *param, int len)
+{
+       char text[64];
+
+       /* change to active state */
+       cryptman_state(CM_ST_SACTIVE);
+       /* send message to user */
+       SPRINT(text, "Call Secure");
+       cryptman_msg2user(CU_ACTS_CONF, text);
+}
+
+/* user requests info */
+void EndpointAppPBX::cr_info(int message, unsigned char *param, int len)
+{
+       /* send message to user */
+       cryptman_msg2user(CU_INFO_CONF, e_crypt_info);
+}
+
+
+CM_MSG_NAMES
+
+void EndpointAppPBX::cryptman_message(int message, unsigned char *param, int len)
+{
+       char *msgtext = "<<UNKNOWN MESSAGE>>";
+
+       if (message>=0 && message<cm_msg_num)
+               msgtext = cm_msg_name[message];
+
+       PDEBUG(DEBUG_CRYPT, "EPOINT(%d) CRYPT MANAGER in state '%s' received message: %s len: %d\n", ea_endpoint->ep_serial, statename(e_crypt_state), msgtext, len);
+
+       /* all states */
+       if (message == CU_INFO_REQ)
+               { cr_info(message, param, len); return; }
+
+       switch(e_crypt_state)
+       {
+               /* in idle state */
+               case CM_ST_NULL:
+               if (message == CU_ACTK_REQ) /* request key-exchange encryption */
+                       { cr_activate(message, param, len); return; }
+               if (message == CU_ACTS_REQ) /* request shared encryption */
+                       { cr_sactivate(message, param, len); return; }
+               break;
+
+               /* identifying state */
+               case CM_ST_IDENT:
+               if (message == CP_IDENT) /* request encryption */
+                       { cr_ident(message, param, len); return; }
+               if (message == CP_SLAVE) /* we are slave */
+                       { cr_slave(message, param, len); return; }
+               if (message == CP_MASTER) /* we are master */
+                       { cr_master(message, param, len); return; }
+               if (message == CP_LOOPED) /* we are looped */
+                       { cr_looped(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CT_TIMEOUT /* timeout */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort(message, param, len); return; }
+               break;
+
+               /* generating public key state */
+               case CM_ST_KEYGEN:
+               if (message == CK_GENRSA_CONF) /* public key is done */
+                       { cr_genrsa(message, param, len); return; }
+               if (message == CK_ERROR_IND) /* key failed */
+                       { cr_keyerror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort_engine(message, param, len); return; }
+               break;
+
+               /* waiting for public key state */
+               case CM_ST_KEYWAIT:
+               if (message == CP_PUBKEY) /* getting public key from remote */
+                       { cr_pubkey(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CT_TIMEOUT /* timeout */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort(message, param, len); return; }
+               break;
+
+               /* generating crypted session key state */
+               case CM_ST_CSKEY:
+               if (message == CK_CPTRSA_CONF) /* crypted session key is done */
+                       { cr_cptrsa(message, param, len); return; }
+               if (message == CK_ERROR_IND) /* key failed */
+                       { cr_keyerror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort_engine(message, param, len); return; }
+               break;
+
+               /* waiting for crypted session key state */
+               case CM_ST_CSWAIT:
+               if (message == CP_CSKEY) /* getting crypted session key from remote */
+                       { cr_cskey(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CT_TIMEOUT /* timeout */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort(message, param, len); return; }
+               break;
+
+               /* generating decrypted session key state */
+               case CM_ST_SESSION:
+               if (message == CK_DECRSA_CONF) /* decrypted is done */
+                       { cr_decrsa(message, param, len); return; }
+               if (message == CK_ERROR_IND) /* key failed */
+                       { cr_keyerror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort_engine(message, param, len); return; }
+               break;
+
+               /* wait encryption on state */
+               case CM_ST_WAIT_DELAY:
+               if (message == CT_TIMEOUT) /* timeout of delay */
+                       { cr_waitdelay(message, param, len); return; }
+               if (message == CC_ERROR_IND) /* encrpytion error */
+                       { cr_crypterror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort_wait(message, param, len); return; }
+               break;
+
+               /* wait encryption on state */
+               case CM_ST_WAIT_CRYPT:
+               if (message == CC_ACTBF_CONF) /* encrpytion active */
+                       { cr_bfactive(message, param, len); return; }
+               if (message == CC_ERROR_IND) /* encrpytion error */
+                       { cr_crypterror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort_wait(message, param, len); return; }
+               break;
+
+               /* active state */
+               case CM_ST_ACTIVE:
+               if (message == CU_DACT_REQ) /* deactivating encryption */
+                       { cr_deactivate(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND /* request aborting */
+                || message == CP_ABORT) /* request aborting */
+                       { cr_abort(message, param, len); return; }
+               break;
+
+
+               /* engine done after abort state */
+               case CM_ST_RELEASE:
+               if (message == CK_GENRSA_CONF /* engine done */
+                || message == CK_CPTRSA_CONF /* engine done */
+                || message == CK_DECRSA_CONF /* engine done */
+                || message == CK_ERROR_IND) /* engine error */
+                       { cr_release(message, param, len); return; }
+               break;
+
+               /* shared active state */
+               case CM_ST_SACTIVE:
+               if (message == CU_DACT_REQ) /* deactivating encryption */
+                       { cr_sdeactivate(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND) /* request aborting */
+                       { cr_sabort(message, param, len); return; }
+               break;
+
+               /* wait shared encryption on state */
+               case CM_ST_SWAIT:
+               if (message == CC_ACTBF_CONF) /* encrpytion active */
+                       { cr_sbfactive(message, param, len); return; }
+               if (message == CC_ERROR_IND) /* encrpytion error */
+                       { cr_scrypterror(message, param, len); return; }
+               if (message == CI_DISCONNECT_IND) /* request aborting */
+                       { cr_sabort(message, param, len); return; }
+               break;
+
+       }
+
+       PDEBUG(DEBUG_CRYPT, "message not handled in state %d\n", e_crypt_state);
+}
+
+
+/*
+ * analyze the message element within the received message from peer and call 'cryptman_message'
+ */
+void EndpointAppPBX::cryptman_msg2man(unsigned char *param, int len)
+{
+       unsigned char *p;
+       unsigned char msg;
+       int i, l;
+
+       /* check if frame is correct */
+       PDEBUG(DEBUG_CRYPT, "EPOINT(%d) message from peer to crypt_manager.\n", ea_endpoint->ep_serial);
+       if (len == 0)
+       {
+               PDEBUG(DEBUG_CRYPT, "ignoring message with 0-length.\n");
+               return;
+       }
+       i = 0;
+       p = param;
+       while(*p)
+       {
+               if (i == len)
+               {
+                       PDEBUG(DEBUG_CRYPT, "end of message without 0-termination.\n");
+                       return;
+               }
+               if (i+3 > len)
+               {
+                       PDEBUG(DEBUG_CRYPT, "message with element size, outside the frame length.\n");
+                       return;
+               }
+               l = (p[1]<<8) + p[2];
+//             PDEBUG(DEBUG_CRYPT, "   inf %d (len = %d)\n", *p, l);
+               if (i+3+l > len)
+               {
+                       PDEBUG(DEBUG_CRYPT, "message with element data, outside the frame length.\n");
+                       return;
+               }
+               i += l + 3;
+               p += l + 3;
+       }
+       if (i+1 != len)
+       {
+               PDEBUG(DEBUG_CRYPT, "warning: received null-element before end of frame.\n");
+       }
+
+       l = CM_SIZEOFINF(CM_INFO_MESSAGE);
+       if (l != 1)
+       {
+               PDEBUG(DEBUG_CRYPT, "received message without (valid) message element (len = %d)\n", len);
+               return;
+       }
+       CM_GETINF(CM_INFO_MESSAGE, &msg);
+       switch (msg)
+       {
+               case CMSG_IDENT:
+               cryptman_message(CP_IDENT, param, len);
+               break;
+               case CMSG_SLAVE:
+               cryptman_message(CP_SLAVE, param, len);
+               break;
+               case CMSG_MASTER:
+               cryptman_message(CP_MASTER, param, len);
+               break;
+               case CMSG_PUBKEY:
+               cryptman_message(CP_PUBKEY, param, len);
+               break;
+               case CMSG_CSKEY:
+               cryptman_message(CP_CSKEY, param, len);
+               break;
+               case CMSG_ABORT:
+               cryptman_message(CP_ABORT, param, len);
+               break;
+               default:
+               PDEBUG(DEBUG_CRYPT, "received unknown message element %d\n", msg);
+       }
+}
+
+/* add information element to buffer
+ */
+void EndpointAppPBX::cryptman_addinf(unsigned char *buf, int buf_size, int element, int len, void *data)
+{
+       int l;
+
+       /* skip what we already have in the buffer */
+       while (buf[0])
+       {
+               l = (buf[1]<<8) + buf[2];
+               if (l >= buf_size-3)
+               {
+                       PERROR("EPOINT(%d) buffer overflow while adding information to peer message.\n", ea_endpoint->ep_serial);
+                       return;
+               }
+               buf_size -= l + 3;
+               buf += l + 3;
+       }
+       /* check if we have not enough space to add element including id, len, data, and the null-termination */
+       if (len+4 > buf_size)
+       {
+               PERROR("EPOINT(%d) cannot add element to message, because buffer would overflow.\n", ea_endpoint->ep_serial);
+               return;
+       }
+       buf[0] = element;
+       buf[1] = len >> 8;
+       buf[2] = len;
+       memcpy(buf+3, data, len);
+}
+
+
+/* get size of element in buffer
+ */
+int EndpointAppPBX::cryptman_sizeofinf(unsigned char *buf, int element)
+{
+       int l;
+
+       /* skip what we already have in the buffer */
+       while (buf[0])
+       {
+               l = (buf[1]<<8) + buf[2];
+               if (buf[0] == element)
+                       return(l);
+               buf += l + 3;
+       }
+       return(-1);
+}
+
+
+/* get information element from buffer
+ */
+unsigned char *EndpointAppPBX::cryptman_getinf(unsigned char *buf, int element, unsigned char *to)
+{
+       int l;
+
+       /* skip what we already have in the buffer */
+       while (buf[0])
+       {
+               l = (buf[1]<<8) + buf[2];
+               if (buf[0] == element)
+               {
+                       memcpy(to, buf+3, l);
+                       return(to);
+               }
+               buf += l + 3;
+       }
+       return(NULL);
+}
+
+
+/* send message to peer
+ */
+void EndpointAppPBX::cryptman_msg2peer(unsigned char *buf)
+{
+       struct message *message;
+       unsigned char *p = buf;
+       int len = 0;
+       int l;
+
+       /* get len */
+       while(p[0])
+       {
+               l = (p[1]<<8) + p[2];
+               len += l + 3;
+               p += l + 3;
+       }
+       if (len+1 > (int)sizeof(message->param.crypt.data))
+       {
+               PERROR("EPOINT(%d) message larger than allowed in param->crypt.data.\n", ea_endpoint->ep_serial);
+               return;
+       }
+       /* send message */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CRYPT);
+       message->param.crypt.type = CR_MESSAGE_REQ;
+       message->param.crypt.len = len+1;
+       memcpy(message->param.crypt.data, buf, len+1);
+       message_put(message);
+
+       if (options.deb & DEBUG_CRYPT)
+       {
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) sending message\n", ea_endpoint->ep_serial);
+               p = buf;
+               while(p[0])
+               {
+                       l = (p[1]<<8) + p[2];
+                       PDEBUG(DEBUG_CRYPT, "   inf %d (len = %d)\n", p[0], l);
+                       len += l + 3;
+                       p += l + 3;
+               }
+       }
+}
+
+/* send message to crypt engine
+ */
+void EndpointAppPBX::cryptman_msg2crengine(int msg, unsigned char *buf, int len)
+{
+       struct message *message;
+
+       if (len > (int)sizeof(message->param.crypt.data))
+       {
+               PERROR("EPOINT(%d) message larger than allowed in param->crypt.data.\n", ea_endpoint->ep_serial);
+               return;
+       }
+       /* send message */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CRYPT);
+       message->param.crypt.type = msg;
+       message->param.crypt.len = len;
+       if (len)
+               memcpy(message->param.crypt.data, buf, len);
+       message_put(message);
+
+       if (options.deb & DEBUG_CRYPT)
+       {
+               char *msgtext = "<<UNKNOWN MESSAGE>>";
+
+               if (msg>=0 && msg<cm_msg_num)
+                       msgtext = cm_msg_name[msg];
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) sending message '%s' (len = %d)\n", ea_endpoint->ep_serial, msgtext, len);
+       }
+}
+
+/* send message to user
+ */
+void EndpointAppPBX::cryptman_msg2user(int msg, char *text)
+{
+       struct message *message;
+       /* send message */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+       message->param.crypt.type = msg;
+       if (!text)
+               text = "";
+       SCPY(e_crypt_info, text);
+       if (text[0])
+       {
+               UNCPY((char *)message->param.crypt.data, e_crypt_info, sizeof(message->param.crypt.data)-1);
+               message->param.crypt.len = strlen((char *)message->param.crypt.data)+1;
+       }
+       message_put(message);
+
+       if (options.deb & DEBUG_CRYPT)
+       {
+               char *msgtext = "<<UNKNOWN MESSAGE>>";
+
+               if (msg>=0 && msg<cm_msg_num)
+                       msgtext = cm_msg_name[msg];
+               PDEBUG(DEBUG_CRYPT, "EPOINT(%d) sending message '%s' (text = %s)\n", ea_endpoint->ep_serial, msgtext, text?text:"");
+       }
+}
+
+/* change state
+ */
+void EndpointAppPBX::cryptman_state(int state)
+{
+       PDEBUG(DEBUG_CRYPT, "Changing state from %s to %s\n", statename(e_crypt_state), statename(state));
+       e_crypt_state = state;
+}
+
+
+/* set timeout
+ */
+void EndpointAppPBX::cryptman_timeout(int secs)
+{
+       if (secs)
+       {
+               e_crypt_timeout_sec = now_tv.tv_sec+secs;
+               e_crypt_timeout_usec = now_tv.tv_usec;
+               PDEBUG(DEBUG_CRYPT, "Changing timeout to %d seconds\n", secs);
+       } else
+       {
+               e_crypt_timeout_sec = 0;
+               e_crypt_timeout_usec = 0;
+               PDEBUG(DEBUG_CRYPT, "turning timeout off\n", secs);
+       }
+}
+
+/* encode a message to be sent via b-channel
+ */
+int cryptman_encode_bch(unsigned char *data, int len, unsigned char *buf, int buf_len)
+{
+       unsigned long crc;
+       int overhead = 18;
+
+       len--; /* without null-termination */
+       if (buf_len < len+overhead)
+       {
+               PERROR("frame too long for buffer");
+               return(0);
+       }
+       PDEBUG(DEBUG_CRYPT, "encoding a block of %d bytes.\n", len);
+
+       /* write identification sequence to the header */
+       UNCPY((char *)buf, "CRYPTMAN" ,8);
+       buf += 8;
+       /* length + checksumme */
+       buf[0] = len >> 8;
+       buf[1] = len & 0xff;
+       crc = crc32(buf, 2);
+       buf += 2;
+       buf[0] = crc >> 24;
+       buf[1] = crc >> 16;
+       buf[2] = crc >> 8;
+       buf[3] = crc;
+       buf += 4;
+       /* data + checksumme */
+       memcpy(buf, data, len);
+       crc = crc32(buf, len);
+       buf += len;
+       buf[0] = crc >> 24;
+       buf[1] = crc >> 16;
+       buf[2] = crc >> 8;
+       buf[3] = crc;
+       buf += 4;
+       return(len + overhead);
+}
+       
+/* decode a message from b-channel
+ */
+void PmISDN::cryptman_listen_bch(unsigned char *p, int l)
+{
+       int i;
+       struct message *message;
+
+       retry:
+       if (!l)
+               return;
+
+       /* check for the keyword */
+       if (p_m_crypt_listen_state == 0)
+       {
+               while((*p++)!='C' && l)
+                       l--;
+               if (!l)
+                       return;
+               l--;
+               p_m_crypt_listen_state++;
+               if (!l)
+                       return;
+       }
+       if (p_m_crypt_listen_state < 8)
+       {
+               i = p_m_crypt_listen_state;
+               while(i < 8)
+               {
+                       l--;
+                       if (*p++ != "CRYPTMAN"[i])
+                       {
+                               p_m_crypt_listen_state = 0;
+                               goto retry;
+                       }
+                       p_m_crypt_listen_state++;
+                       if (!l)
+                               break;
+                       i++;
+               }
+               if (!l)
+                       return;
+       }
+       /* high byte of length */
+       if (p_m_crypt_listen_state == 8)
+       {
+               p_m_crypt_listen_len = (*p++) << 8;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       /* low byte of length */
+       if (p_m_crypt_listen_state == 9)
+       {
+               p_m_crypt_listen_len += *p++;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       /* crc */
+       if (p_m_crypt_listen_state == 10)
+       {
+               p_m_crypt_listen_crc = (*p++) << 24;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 11)
+       {
+               p_m_crypt_listen_crc += (*p++) << 16;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 12)
+       {
+               p_m_crypt_listen_crc += (*p++) << 8;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 13)
+       {
+               unsigned char lencheck[2];
+               p_m_crypt_listen_crc += *p++;
+               /* check for CRC */
+               lencheck[0] = p_m_crypt_listen_len >> 8;
+               lencheck[1] = p_m_crypt_listen_len & 0xff;
+               if (crc32(lencheck, 2) != p_m_crypt_listen_crc)
+               {
+                       PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of %d bytes, but checksumme of length is incorrect (must %08x is %08x\n", p_name, p_m_crypt_listen_len, crc32(lencheck, 2), p_m_crypt_listen_crc);
+                       p_m_crypt_listen_state = 0;
+                       goto retry;
+               }
+               if (p_m_crypt_listen_len > (int)sizeof(p_m_crypt_listen_msg))
+               {
+                       PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of %d bytes, but too big for buffer (%d bytes)\n", p_name, p_m_crypt_listen_len, sizeof(p_m_crypt_listen_msg));
+                       p_m_crypt_listen_state = 0;
+                       goto retry;
+               }
+               if (!p_m_crypt_listen_len)
+               {
+                       PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of 0 bytes\n", p_name);
+                       p_m_crypt_listen_state = 0;
+                       goto retry;
+               }
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       /* read message */
+       while (p_m_crypt_listen_state>=14 && p_m_crypt_listen_state<(p_m_crypt_listen_len+14))
+       {
+               p_m_crypt_listen_msg[p_m_crypt_listen_state-14] = *p++;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       /* crc */
+       if (p_m_crypt_listen_state == 14+p_m_crypt_listen_len)
+       {
+               p_m_crypt_listen_crc = (*p++) << 24;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 15+p_m_crypt_listen_len)
+       {
+               p_m_crypt_listen_crc += (*p++) << 16;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 16+p_m_crypt_listen_len)
+       {
+               p_m_crypt_listen_crc += (*p++) << 8;
+               p_m_crypt_listen_state++;
+               if (!(--l))
+                       return;
+       }
+       if (p_m_crypt_listen_state == 17+p_m_crypt_listen_len)
+       {
+               l--;
+               p_m_crypt_listen_crc += *p++;
+               /* check for CRC */
+               if (crc32(p_m_crypt_listen_msg, p_m_crypt_listen_len) != p_m_crypt_listen_crc)
+               {
+                       PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of %d bytes, but checksumme of data block is incorrect\n", p_name, p_m_crypt_listen_len);
+                       p_m_crypt_listen_state = 0;
+                       if (!l)
+                               return;
+                       goto retry;
+               }
+               /* now send message */
+               p_m_crypt_listen_state = 0;
+               PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of %d bytes sending to crypt manager\n", p_name, p_m_crypt_listen_len);
+               if ((int)sizeof(message->param.crypt.data) < p_m_crypt_listen_len+1) /* null-terminated */
+               {
+                       PDEBUG(DEBUG_CRYPT, "PmISDN(%s) received a block of %d bytes that is too large for message buffer\n", p_name, p_m_crypt_listen_len);
+                       if (!l)
+                               return;
+                       goto retry;
+               }
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CRYPT);
+               message->param.crypt.type = CR_MESSAGE_IND;
+               message->param.crypt.len = p_m_crypt_listen_len+1; /* null termination */
+               memcpy(message->param.crypt.data, p_m_crypt_listen_msg, p_m_crypt_listen_len);
+               message_put(message);
+               p_m_crypt_listen_state = 0;
+               if (!l)
+                       return;
+               goto retry;
+       }
+}
+
+
+/* encrypt call using share secret (keypad function)
+ */
+void EndpointAppPBX::encrypt_shared(void)
+{
+       struct message *message;
+       char *errstr = "";
+       class Port *port;
+       int type, key_len;
+       unsigned char *key;
+       char *auth_pointer, *crypt_pointer, *key_pointer;
+       int ret;
+
+       /* redisplay current crypt display */
+       if (e_crypt != CRYPT_OFF)
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption in progress, so we request the current message.\n", ea_endpoint->ep_serial);
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+               message->param.crypt.type = CU_INFO_REQ;
+               message_put(message);
+               return;
+       }
+
+       if (check_external(&errstr, &port))
+       {
+               reject:
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+               SCPY(message->param.notifyinfo.display, errstr);
+               message_put(message);
+               set_tone(ea_endpoint->ep_portlist, "crypt_off");
+               e_tone[0] = '\0';
+               return;
+       }
+
+       /* check the key for the call */
+       if (port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_SIP_OUT)
+               ret = parse_secrets((char *)e_terminal, (char *)port->p_dialinginfo.number, &auth_pointer, &crypt_pointer, &key_pointer);
+       else
+       {
+               if (!port->p_callerinfo.id[0])
+               {
+                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming remote call has no caller ID.\n", ea_endpoint->ep_serial);
+                       errstr = "No Remote ID";
+                       goto reject;
+               }
+               ret = parse_secrets((char *)e_terminal, (char *)numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype), &auth_pointer, &crypt_pointer, &key_pointer);
+       }
+       if (!ret)
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key was not found.\n", ea_endpoint->ep_serial);
+               errstr = "No Key";
+               goto reject;
+       }
+       key = crypt_key((unsigned char *)key_pointer, &key_len);
+       if (!key)
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key invalid.\n", ea_endpoint->ep_serial);
+               errstr = "Invalid Key";
+               goto reject;
+       }
+       if (key_len > 128)
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key too long.\n", ea_endpoint->ep_serial);
+               errstr = "Key Too Long";
+               goto reject;
+       }
+       if (!!strcasecmp(auth_pointer, "manual"))
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Wrong authentication method.\n", ea_endpoint->ep_serial);
+               errstr = "Wrong Auth Type";
+               goto reject;
+       }
+       if (!strcasecmp(crypt_pointer, "blowfish"))
+       {
+               type = CC_ACTBF_REQ;
+               if (key_len < 4)
+               {
+                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key too short.\n", ea_endpoint->ep_serial);
+                       errstr = "Key Too Short";
+                       goto reject;
+               }
+               if (key_len > 56)
+               {
+                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key too long.\n", ea_endpoint->ep_serial);
+                       errstr = "Key Too Long";
+                       goto reject;
+               }
+       } else
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Wrong crypt method.\n", ea_endpoint->ep_serial);
+               errstr = "Wrong Crypt Type";
+               goto reject;
+       }
+
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Key is ok, sending activation+key to cryptman.\n", ea_endpoint->ep_serial);
+       /* setting display message and state */
+//     SPRINT(e_crypt_display, "Shared Key");
+       e_crypt = CRYPT_SWAIT;
+       /* sending activation */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+       message->param.crypt.type = CU_ACTS_REQ;
+       message->param.crypt.len = key_len;
+       memcpy(message->param.crypt.data, key, key_len);
+       message_put(message);
+}
+
+
+/* encrypt call using rsa authentication (keypad function)
+ */
+void EndpointAppPBX::encrypt_keyex(void)
+{
+       struct message *message;
+       char *errstr = "";
+       class Port *port;
+
+       /* redisplay current crypt display */
+       if (e_crypt != CRYPT_OFF)
+       {
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption in progress, so we request the current message.\n", ea_endpoint->ep_serial);
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+               message->param.crypt.type = CU_INFO_REQ;
+               message_put(message);
+               return;
+       }
+
+
+       if (check_external(&errstr, &port))
+       {
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+               SCPY(message->param.notifyinfo.display, errstr);
+               message_put(message);
+               set_tone(ea_endpoint->ep_portlist, "crypt_off");
+               e_tone[0] = '\0';
+               return;
+       }
+
+#ifndef CRYPTO
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+       SCPY(message->param.notifyinfo.display, "Not Compiled");
+       message_put(message);
+       set_tone(ea_endpoint->ep_portlist, "crypt_off");
+       e_tone[0] = '\0';
+#else
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Sending key-exchange activation to cryptman.\n", ea_endpoint->ep_serial);
+       /* setting display message and state */
+//     SPRINT(e_crypt_display, "Key-Exchange");
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+       SCPY(message->param.notifyinfo.display, "Key-Exchange");
+       message_put(message);
+       e_crypt = CRYPT_KWAIT;
+       /* sending activation */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+       message->param.crypt.type = CU_ACTK_REQ;
+       message_put(message);
+#endif /* CRYPTO */
+}
+
+
+/* turn encryption off (keypad function)
+ */
+void EndpointAppPBX::encrypt_off(void)
+{
+       struct message *message;
+
+       if (e_crypt!=CRYPT_ON && e_crypt!=CRYPT_OFF)
+       {
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+               SCPY(message->param.notifyinfo.display, "Please Wait");
+               message_put(message);
+               return;
+       }
+       if (e_crypt == CRYPT_OFF)
+       {
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+               SCPY(message->param.notifyinfo.display, "No Encryption");
+               message_put(message);
+               set_tone(ea_endpoint->ep_portlist, "crypt_off");
+               e_tone[0] = '\0';
+               return;
+       }
+
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) Sending deactivation to cryptman.\n", ea_endpoint->ep_serial);
+       /* setting display message and state */
+//     SPRINT(e_crypt_display, "Deactivating");
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+       SCPY(message->param.notifyinfo.display, "Deactivating");
+       message_put(message);
+       e_crypt = CRYPT_RELEASE;
+       /* sending activation */
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CRYPT);
+       message->param.crypt.type = CU_DACT_REQ;
+       message_put(message);
+}
+
+
+/* messages from manager to endpoint
+ */
+void EndpointAppPBX::encrypt_result(int msg, char *text)
+{
+       struct message *message;
+
+       switch(msg)
+       {
+               case CU_ACTK_CONF:
+               case CU_ACTS_CONF:
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption now active.\n", ea_endpoint->ep_serial);
+               set_tone(ea_endpoint->ep_portlist, "crypt_on");
+               e_tone[0] = '\0';
+               e_crypt = CRYPT_ON;
+               display:
+               if (text) if (text[0])
+               {
+                       SCPY(e_crypt_info, text);
+                       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+                       SCPY(message->param.notifyinfo.display, e_crypt_info);
+                       message_put(message);
+               }
+               break;
+
+               case CU_ERROR_IND:
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption error. (%s)\n", ea_endpoint->ep_serial, text);
+               set_tone(ea_endpoint->ep_portlist, "crypt_off");
+               e_tone[0] = '\0';
+               e_crypt = CRYPT_OFF;
+               goto display;
+               break;
+
+               case CU_DACT_CONF:
+               case CU_DACT_IND:
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption now off. (%s)\n", ea_endpoint->ep_serial, text);
+               set_tone(ea_endpoint->ep_portlist, "crypt_off");
+               e_tone[0] = '\0';
+               e_crypt = CRYPT_OFF;
+               goto display;
+               break;
+
+               case CU_INFO_CONF:
+               case CU_INFO_IND:
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) information. (%s)\n", ea_endpoint->ep_serial, text);
+               goto display;
+               break;
+
+               default:
+               PERROR("EPOINT(%d) crypt manager sends us an invalid message. (type = %d)\n", ea_endpoint->ep_serial, msg);
+       }
+}
+