1 /**
2  * (C) 2007-20 - ntop.org and contributors
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not see see <http://www.gnu.org/licenses/>
16  *
17  */
18 
19 #include "n2n.h"
20 
21 #define N2N_TWOFISH_NUM_SA              32 /* space for SAa */
22 
23 #define N2N_TWOFISH_TRANSFORM_VERSION   1  /* version of the transform encoding */
24 
25 typedef struct transop_tf {
26   TWOFISH*           enc_tf; /* tx state */
27   TWOFISH*           dec_tf; /* rx state */
28 } transop_tf_t;
29 
transop_deinit_twofish(n2n_trans_op_t * arg)30 static int transop_deinit_twofish( n2n_trans_op_t * arg ) {
31   transop_tf_t *priv = (transop_tf_t *)arg->priv;
32 
33   if(priv) {
34     TwoFishDestroy(priv->enc_tf); /* deallocate TWOFISH */
35     TwoFishDestroy(priv->dec_tf); /* deallocate TWOFISH */
36     free(priv);
37   }
38 
39   return 0;
40 }
41 
42 #define TRANSOP_TF_VER_SIZE     1       /* Support minor variants in encoding in one module. */
43 #define TRANSOP_TF_NONCE_SIZE   4
44 #define TRANSOP_TF_SA_SIZE      4
45 
46 /** The twofish packet format consists of:
47  *
48  *  - a 8-bit twofish encoding version in clear text
49  *  - a 32-bit SA number in clear text
50  *  - ciphertext encrypted from a 32-bit nonce followed by the payload.
51  *
52  *  [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
53  *         |<------ encrypted ------>|
54  */
transop_encode_twofish(n2n_trans_op_t * arg,uint8_t * outbuf,size_t out_len,const uint8_t * inbuf,size_t in_len,const uint8_t * peer_mac)55 static int transop_encode_twofish( n2n_trans_op_t * arg,
56                                    uint8_t * outbuf,
57                                    size_t out_len,
58                                    const uint8_t * inbuf,
59                                    size_t in_len,
60 				   const uint8_t * peer_mac)
61 {
62   int len=-1;
63   transop_tf_t * priv = (transop_tf_t *)arg->priv;
64   uint8_t assembly[N2N_PKT_BUF_SIZE];
65   uint32_t * pnonce;
66 
67   if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
68     {
69       if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
70         {
71 	  size_t idx=0;
72 	  uint32_t sa_id=0; // Not used
73 
74 	  traceEvent(TRACE_DEBUG, "encode_twofish %lu", in_len);
75 
76 	  /* Encode the twofish format version. */
77 	  encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
78 
79 	  /* Encode the security association (SA) number */
80 	  encode_uint32( outbuf, &idx, sa_id );
81 
82 	  /* The assembly buffer is a source for encrypting data. The nonce is
83 	   * written in first followed by the packet payload. The whole
84 	   * contents of assembly are encrypted. */
85 	  pnonce = (uint32_t *)assembly;
86 	  *pnonce = n2n_rand();
87 	  memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len );
88 
89 	  /* Encrypt the assembly contents and write the ciphertext after the SA. */
90 	  len = TwoFishEncryptRaw( assembly, /* source */
91 				   outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
92 				   in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
93 				   priv->enc_tf);
94 	  if ( len > 0 )
95             {
96 	      len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
97             }
98 	  else
99             {
100 	      traceEvent( TRACE_ERROR, "encode_twofish encryption failed." );
101             }
102 
103         }
104       else
105         {
106 	  traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." );
107         }
108     }
109   else
110     {
111       traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." );
112     }
113 
114   return len;
115 }
116 
117 /** The twofish packet format consists of:
118  *
119  *  - a 8-bit twofish encoding version in clear text
120  *  - a 32-bit SA number in clear text
121  *  - ciphertext encrypted from a 32-bit nonce followed by the payload.
122  *
123  *  [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
124  *         |<------ encrypted ------>|
125  */
transop_decode_twofish(n2n_trans_op_t * arg,uint8_t * outbuf,size_t out_len,const uint8_t * inbuf,size_t in_len,const uint8_t * peer_mac)126 static int transop_decode_twofish( n2n_trans_op_t * arg,
127                                    uint8_t * outbuf,
128                                    size_t out_len,
129                                    const uint8_t * inbuf,
130                                    size_t in_len,
131 				   const uint8_t * peer_mac)
132 {
133   int len=0;
134   transop_tf_t * priv = (transop_tf_t *)arg->priv;
135   uint8_t assembly[N2N_PKT_BUF_SIZE];
136 
137   if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
138        && (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
139        ) {
140       size_t rem=in_len;
141       size_t idx=0;
142       uint8_t tf_enc_ver=0;
143       uint32_t sa_rx=0; // Not used
144 
145       /* Get the encoding version to make sure it is supported */
146       decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
147 
148       if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver ) {
149 	  /* Get the SA number and make sure we are decrypting with the right one. */
150 	  decode_uint32( &sa_rx, inbuf, &rem, &idx );
151 
152 	  traceEvent(TRACE_DEBUG, "decode_twofish %lu", in_len);
153 
154 	  len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
155 				     assembly, /* destination */
156 				     (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
157 				     priv->dec_tf);
158 
159 	  if(len > 0) {
160 	    /* Step over 4-byte random nonce value */
161 	    len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
162 
163 	    memcpy( outbuf,
164 		    assembly + TRANSOP_TF_NONCE_SIZE,
165 		    len );
166 	  } else
167 	    traceEvent(TRACE_ERROR, "decode_twofish decryption failed");
168       } else
169 	traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
170   } else
171     traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
172 
173   return len;
174 }
175 
transop_tick_twofish(n2n_trans_op_t * arg,time_t now)176 static void transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) {}
177 
178 /* Twofish initialization function */
n2n_transop_twofish_init(const n2n_edge_conf_t * conf,n2n_trans_op_t * ttt)179 int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
180   transop_tf_t *priv;
181   const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
182   size_t encrypt_key_len = strlen(conf->encrypt_key);
183 
184   memset(ttt, 0, sizeof(*ttt));
185   ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
186 
187   ttt->tick = transop_tick_twofish;
188   ttt->deinit = transop_deinit_twofish;
189   ttt->fwd = transop_encode_twofish;
190   ttt->rev = transop_decode_twofish;
191 
192   priv = (transop_tf_t*) calloc(1, sizeof(transop_tf_t));
193   if(!priv) {
194     traceEvent(TRACE_ERROR, "cannot allocate transop_tf_t memory");
195     return(-1);
196   }
197   ttt->priv = priv;
198 
199   /* This is a preshared key setup. Both Tx and Rx are using the same security association. */
200   priv->enc_tf = TwoFishInit(encrypt_key, encrypt_key_len);
201   priv->dec_tf = TwoFishInit(encrypt_key, encrypt_key_len);
202 
203   if((!priv->enc_tf) || (!priv->dec_tf)) {
204     if(priv->enc_tf) TwoFishDestroy(priv->enc_tf);
205     if(priv->dec_tf) TwoFishDestroy(priv->dec_tf);
206     free(priv);
207     traceEvent(TRACE_ERROR, "TwoFishInit failed");
208     return(-2);
209   }
210 
211   return(0);
212 }
213