libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 #ifndef MOOST_NAGIOS_NSCA_CRYPTO_HPP__ 00029 #define MOOST_NAGIOS_NSCA_CRYPTO_HPP__ 00030 00031 #include <string> 00032 #include <stdexcept> 00033 00034 #ifdef HAVE_LIBMCRYPT 00035 #include <mcrypt.h> 00036 #endif 00037 00038 #include <boost/scoped_ptr.hpp> 00039 #include <boost/noncopyable.hpp> 00040 00041 #include "nsca_common.hpp" 00042 #include "nsca_data_packet.hpp" 00043 00044 namespace moost{ namespace nagios{ 00045 00046 #ifdef WIN32 00047 inline void bzero(void * p, size_t const size) 00048 { 00049 memset(p, 0, size); 00050 } 00051 #endif 00052 00053 class nsca_crypto: boost::noncopyable 00054 { 00055 private: 00056 struct crypt_instance{ 00057 char transmitted_iv[nsca_const::TRANSMITTED_IV_SIZE]; 00058 #ifdef HAVE_LIBMCRYPT 00059 MCRYPT td; 00060 std::vector<char> key; 00061 std::vector<char> IV; 00062 char block_buffer; 00063 int blocksize; 00064 size_t keysize; 00065 char *mcrypt_algorithm; 00066 char *mcrypt_mode; 00067 #endif 00068 }; 00069 00070 typedef boost::scoped_ptr< crypt_instance > crypt_instance_ptr; 00071 00072 public: 00073 nsca_crypto( 00074 char const * received_iv, 00075 int const method, 00076 std::string const & password 00077 ) 00078 : method_(method) 00079 , password_(password) 00080 , CIptr_(new crypt_instance) 00081 { 00082 encrypt_init(password_.c_str(), method, received_iv, CIptr_); 00083 } 00084 00085 ~nsca_crypto() 00086 { 00087 encrypt_cleanup(method_, CIptr_); 00088 } 00089 00090 void encrypt(nsca_data_packet & packet) const 00091 { 00092 encrypt_buffer( 00093 reinterpret_cast<char *>(&packet), sizeof(packet), 00094 password_.c_str(), method_, CIptr_); 00095 } 00096 00097 void decrypt(nsca_data_packet & packet) const 00098 { 00099 decrypt_buffer( 00100 reinterpret_cast<char *>(&packet), sizeof(packet), 00101 password_.c_str(), method_, CIptr_); 00102 } 00103 00104 private: 00105 //---> NASTY CODE ALERT 00106 // [ricky 7/14/2011] hoiked (and cleaned up a tad) from nsca_send 00107 // 00108 #ifdef HAVE_LIBMCRYPT 00109 void encrypt_init(char const *password,int encryption_method,char const * received_iv, crypt_instance_ptr &CI) const 00110 #else // shut up gcc moaning that password and encryption_method are not used 00111 void encrypt_init(char const *,int encryption_method,char const * received_iv, crypt_instance_ptr &CI) const 00112 #endif 00113 { 00114 00115 /* server generates IV used for encryption */ 00116 if(received_iv==NULL) 00117 throw std::runtime_error("initialization vector not defined"); 00118 00119 /* client recieves IV from server */ 00120 memcpy(CI->transmitted_iv,received_iv,nsca_const::TRANSMITTED_IV_SIZE); 00121 00122 #ifdef HAVE_LIBMCRYPT 00123 CI->blocksize=1; /* block size = 1 byte w/ CFB mode */ 00124 CI->keysize=7; /* default to 56 bit key length */ 00125 CI->mcrypt_mode="cfb"; /* CFB = 8-bit cipher-feedback mode */ 00126 CI->mcrypt_algorithm="unknown"; 00127 #endif 00128 00129 /* XOR or no encryption */ 00130 if(encryption_method==nsca_encryption_method::ENCRYPT_NONE || encryption_method==nsca_encryption_method::ENCRYPT_XOR) 00131 return; 00132 00133 #ifdef HAVE_LIBMCRYPT 00134 00135 /* get the name of the mcrypt encryption algorithm to use */ 00136 switch(encryption_method){ 00137 case nsca_encryption_method::ENCRYPT_DES: 00138 CI->mcrypt_algorithm=MCRYPT_DES; 00139 break; 00140 case nsca_encryption_method::ENCRYPT_3DES: 00141 CI->mcrypt_algorithm=MCRYPT_3DES; 00142 break; 00143 case nsca_encryption_method::ENCRYPT_CAST128: 00144 CI->mcrypt_algorithm=MCRYPT_CAST_128; 00145 break; 00146 case nsca_encryption_method::ENCRYPT_CAST256: 00147 CI->mcrypt_algorithm=MCRYPT_CAST_256; 00148 break; 00149 case nsca_encryption_method::ENCRYPT_XTEA: 00150 CI->mcrypt_algorithm=MCRYPT_XTEA; 00151 break; 00152 case nsca_encryption_method::ENCRYPT_3WAY: 00153 CI->mcrypt_algorithm=MCRYPT_3WAY; 00154 break; 00155 case nsca_encryption_method::ENCRYPT_BLOWFISH: 00156 CI->mcrypt_algorithm=MCRYPT_BLOWFISH; 00157 break; 00158 case nsca_encryption_method::ENCRYPT_TWOFISH: 00159 CI->mcrypt_algorithm=MCRYPT_TWOFISH; 00160 break; 00161 case nsca_encryption_method::ENCRYPT_LOKI97: 00162 CI->mcrypt_algorithm=MCRYPT_LOKI97; 00163 break; 00164 case nsca_encryption_method::ENCRYPT_RC2: 00165 CI->mcrypt_algorithm=MCRYPT_RC2; 00166 break; 00167 case nsca_encryption_method::ENCRYPT_ARCFOUR: 00168 CI->mcrypt_algorithm=MCRYPT_ARCFOUR; 00169 break; 00170 case nsca_encryption_method::ENCRYPT_RIJNDAEL128: 00171 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_128; 00172 break; 00173 case nsca_encryption_method::ENCRYPT_RIJNDAEL192: 00174 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_192; 00175 break; 00176 case nsca_encryption_method::ENCRYPT_RIJNDAEL256: 00177 CI->mcrypt_algorithm=MCRYPT_RIJNDAEL_256; 00178 break; 00179 case nsca_encryption_method::ENCRYPT_WAKE: 00180 CI->mcrypt_algorithm=MCRYPT_WAKE; 00181 break; 00182 case nsca_encryption_method::ENCRYPT_SERPENT: 00183 CI->mcrypt_algorithm=MCRYPT_SERPENT; 00184 break; 00185 case nsca_encryption_method::ENCRYPT_ENIGMA: 00186 CI->mcrypt_algorithm=MCRYPT_ENIGMA; 00187 break; 00188 case nsca_encryption_method::ENCRYPT_GOST: 00189 CI->mcrypt_algorithm=MCRYPT_GOST; 00190 break; 00191 case nsca_encryption_method::ENCRYPT_SAFER64: 00192 CI->mcrypt_algorithm=MCRYPT_SAFER_SK64; 00193 break; 00194 case nsca_encryption_method::ENCRYPT_SAFER128: 00195 CI->mcrypt_algorithm=MCRYPT_SAFER_SK128; 00196 break; 00197 case nsca_encryption_method::ENCRYPT_SAFERPLUS: 00198 CI->mcrypt_algorithm=MCRYPT_SAFERPLUS; 00199 break; 00200 00201 default: 00202 CI->mcrypt_algorithm="unknown"; 00203 break; 00204 } 00205 00206 /* open encryption module */ 00207 if((CI->td=mcrypt_module_open(CI->mcrypt_algorithm,NULL,CI->mcrypt_mode,NULL))==MCRYPT_FAILED){ 00208 throw std::runtime_error("Could not open mcrypt algorithm"); 00209 } 00210 00211 /* determine size of IV buffer for this algorithm */ 00212 size_t iv_size=mcrypt_enc_get_iv_size(CI->td); 00213 if(iv_size>nsca_const::TRANSMITTED_IV_SIZE){ 00214 throw std::runtime_error("IV size for crypto algorithm exceeds limits"); 00215 } 00216 00217 CI->IV.resize(iv_size); 00218 00219 /* fill IV buffer with first bytes of IV that is going to be used to crypt (determined by server) */ 00220 for(size_t i=0;i<iv_size;i++) 00221 CI->IV[i]=CI->transmitted_iv[i]; 00222 00223 /* get maximum key size for this algorithm */ 00224 CI->keysize=mcrypt_enc_get_key_size(CI->td); 00225 00226 CI->key.resize(CI->keysize); 00227 00228 bzero(&CI->key[0],CI->keysize); 00229 00230 if(CI->keysize<strlen(password)) 00231 strncpy(&CI->key[0],password,CI->keysize); 00232 else 00233 strncpy(&CI->key[0],password,strlen(password)); 00234 00235 /* initialize encryption buffers */ 00236 mcrypt_generic_init(CI->td,&CI->key[0],CI->keysize,&CI->IV[0]); 00237 00238 #endif 00239 } 00240 00241 00242 00243 /* encryption routine cleanup */ 00244 #ifdef HAVE_LIBMCRYPT 00245 void encrypt_cleanup(int encryption_method, crypt_instance_ptr const & CI) 00246 #else // shut up gcc moaning encryption_method is not used 00247 void encrypt_cleanup(int, crypt_instance_ptr const & CI) 00248 #endif 00249 { 00250 00251 /* no crypt instance */ 00252 if(!CI) 00253 return; 00254 00255 #ifdef HAVE_LIBMCRYPT 00256 /* mcrypt cleanup */ 00257 if(encryption_method!=nsca_encryption_method::ENCRYPT_NONE && encryption_method!=nsca_encryption_method::ENCRYPT_XOR){ 00258 mcrypt_generic_end(CI->td); 00259 } 00260 #endif 00261 } 00262 00263 /* encrypt a buffer */ 00264 void encrypt_buffer(char *buffer,size_t buffer_size, char const *password, int encryption_method, crypt_instance_ptr const & CI) const 00265 { 00266 size_t x; 00267 size_t y; 00268 size_t password_length; 00269 00270 /* no crypt instance */ 00271 if(!CI) 00272 return; 00273 00274 /* no encryption */ 00275 if(encryption_method==nsca_encryption_method::ENCRYPT_NONE) 00276 return; 00277 00278 /* simple XOR "encryption" - not meant for any real security, just obfuscates data, but its fast... */ 00279 else if(encryption_method==nsca_encryption_method::ENCRYPT_XOR){ 00280 00281 /* rotate over IV we received from the server... */ 00282 for(y=0,x=0;y<buffer_size;y++,x++){ 00283 00284 /* keep rotating over IV */ 00285 if(x>=nsca_const::TRANSMITTED_IV_SIZE) 00286 x=0; 00287 00288 buffer[y]^=CI->transmitted_iv[x]; 00289 } 00290 00291 /* rotate over password... */ 00292 password_length=strlen(password); 00293 for(y=0,x=0;y<buffer_size;y++,x++){ 00294 00295 /* keep rotating over password */ 00296 if(x>=password_length) 00297 x=0; 00298 00299 buffer[y]^=password[x]; 00300 } 00301 00302 return; 00303 } 00304 00305 #ifdef HAVE_LIBMCRYPT 00306 /* use mcrypt routines */ 00307 else{ 00308 00309 /* encrypt each byte of buffer, one byte at a time (CFB mode) */ 00310 for(x=0;x<buffer_size;x++) 00311 mcrypt_generic(CI->td,&buffer[x],1); 00312 } 00313 #endif 00314 00315 return; 00316 } 00317 00318 00319 /* decrypt a buffer */ 00320 void decrypt_buffer(char *buffer,size_t buffer_size, char const*password, int encryption_method, crypt_instance_ptr const &CI) const 00321 { 00322 00323 /* no crypt instance */ 00324 if(CI==NULL) 00325 return; 00326 00327 /* no encryption */ 00328 if(encryption_method==nsca_encryption_method::ENCRYPT_NONE) 00329 return; 00330 00331 /* XOR "decryption" is the same as encryption */ 00332 else if(encryption_method==nsca_encryption_method::ENCRYPT_XOR) 00333 encrypt_buffer(buffer,buffer_size,password,encryption_method,CI); 00334 00335 #ifdef HAVE_LIBMCRYPT 00336 /* use mcrypt routines */ 00337 else{ 00338 00339 /* encrypt each byte of buffer, one byte at a time (CFB mode) */ 00340 for(size_t x=0;x<buffer_size;x++) 00341 mdecrypt_generic(CI->td,&buffer[x],1); 00342 } 00343 #endif 00344 00345 return; 00346 } 00347 // ---< 00348 00349 int method_; 00350 std::string password_; 00351 crypt_instance_ptr CIptr_; 00352 }; 00353 00354 }} 00355 00356 #endif