* A plugin to test the ciphers that ship with purple * Copyright (C) 2004, Gary Kramlich <amc_grim@users.sf.net> * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #include "ciphers/aescipher.h" #include "ciphers/md5hash.h" #include "ciphers/pbkdf2cipher.h" #include "ciphers/sha1hash.h" #include "ciphers/sha256hash.h" /************************************************************************** **************************************************************************/ struct test md5_tests [ 8 ] = { { "" , "d41d8cd98f00b204e9800998ecf8427e" }, { "a" , "0cc175b9c0f1b6a831c399e269772661" }, { "abc" , "900150983cd24fb0d6963f7d28e17f72" }, { "message digest" , "f96b697d7cb7938d525a2f31aaf161d0" }, { "abcdefghijklmnopqrstuvwxyz" , "c3fcd3d76192e4007dfb496cca67e13b" }, { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" , "d174ab98d277d9f5a5611c2c9f419d9f" }, { "123456789012345678901234567" "890123456789012345678901234" "56789012345678901234567890" , "57edf4a22be3c955ac49da2e2107b67a" }, hash = purple_md5_hash_new (); purple_debug_info ( "cipher-test" , "could not find md5 cipher, not testing \n " ); purple_debug_info ( "cipher-test" , "Running md5 tests \n " ); while ( md5_tests [ i ]. answer ) { purple_debug_info ( "cipher-test" , "Test %02d: \n " , i ); purple_debug_info ( "cipher-test" , "Testing '%s' \n " , md5_tests [ i ]. question ); purple_hash_append ( hash , ( guchar * ) md5_tests [ i ]. question , strlen ( md5_tests [ i ]. question )); ret = purple_hash_digest_to_str ( hash , digest , sizeof ( digest )); purple_debug_info ( "cipher-test" , "failed \n " ); purple_debug_info ( "cipher-test" , " \t Got: %s \n " , digest ); purple_debug_info ( "cipher-test" , " \t Wanted: %s \n " , purple_debug_info ( "cipher-test" , "md5 tests completed \n\n " ); /************************************************************************** **************************************************************************/ struct test sha1_tests [ 5 ] = { { "a" , "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8" }, { "abc" , "a9993e364706816aba3e25717850c26c9cd0d89d" } , { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" , "84983e441c3bd26ebaae4aa1f95129e5e54670f1" } , { NULL , "34aa973cd4c4daa4f61eeb2bdbad27316534016f" }, hash = purple_sha1_hash_new (); purple_debug_info ( "cipher-test" , "could not find sha1 cipher, not testing \n " ); purple_debug_info ( "cipher-test" , "Running sha1 tests \n " ); while ( sha1_tests [ i ]. answer ) { purple_debug_info ( "cipher-test" , "Test %02d: \n " , i ); purple_debug_info ( "cipher-test" , "Testing '%s' \n " , ( sha1_tests [ i ]. question != NULL ) ? sha1_tests [ i ]. question : "'a'x1000, 1000 times" ); if ( sha1_tests [ i ]. question ) { purple_hash_append ( hash , ( guchar * ) sha1_tests [ i ]. question , strlen ( sha1_tests [ i ]. question )); for ( j = 0 ; j < 1000 ; j ++ ) purple_hash_append ( hash , buff , 1000 ); ret = purple_hash_digest_to_str ( hash , digest , sizeof ( digest )); purple_debug_info ( "cipher-test" , "failed \n " ); purple_debug_info ( "cipher-test" , " \t Got: %s \n " , digest ); purple_debug_info ( "cipher-test" , " \t Wanted: %s \n " , purple_debug_info ( "cipher-test" , "sha1 tests completed \n\n " ); const gchar * nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093" ; const gchar * client_nonce = "0a4f113b" ; const gchar * username = "Mufasa" ; const gchar * realm = "testrealm@host.com" ; const gchar * password = "Circle Of Life" ; const gchar * algorithm = "md5" ; const gchar * nonce_count = "00000001" ; const gchar * method = "GET" ; const gchar * qop = "auth" ; const gchar * digest_uri = "/dir/index.html" ; const gchar * entity = NULL ; purple_debug_info ( "cipher-test" , "Running HTTP Digest tests \n " ); session_key = purple_http_digest_calculate_session_key ( algorithm , username , realm , password , purple_debug_info ( "cipher-test" , "purple_cipher_http_digest_calculate_session_key failed. \n " ); purple_debug_info ( "cipher-test" , " \t session_key: Got: %s \n " , session_key ); purple_debug_info ( "cipher-test" , " \t session_key: Wanted: %s \n " , "939e7578ed9e3c518a452acee763bce9" ); response = purple_http_digest_calculate_response ( algorithm , method , digest_uri , qop , entity , nonce , nonce_count , client_nonce , session_key ); purple_debug_info ( "cipher-test" , "purple_cipher_http_digest_calculate_session_key failed. \n " ); purple_debug_info ( "cipher-test" , " \t response: Got: %s \n " , response ); purple_debug_info ( "cipher-test" , " \t response: Wanted: %s \n " , "6629fae49393a05397450978507c4ef1" ); purple_debug_info ( "cipher-test" , "HTTP Digest tests completed \n\n " ); /************************************************************************** **************************************************************************/ pbkdf2_test pbkdf2_tests [] = { { "sha256" , 1 , "password" , "salt" , 32 , "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b" }, { "sha1" , 1 , "password" , "salt" , 32 , "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164" }, { "sha1" , 1000 , "ala ma kota" , "" , 16 , "924dba137b5bcf6d0de84998f3d8e1f9" }, { "sha1" , 1 , "" , "" , 32 , "1e437a1c79d75be61e91141dae20affc4892cc99abcc3fe753887bccc8920176" }, { "sha256" , 100 , "some password" , "and salt" , 1 , "c7" }, { "sha1" , 10000 , "pretty long password W Szczebrzeszynie chrzaszcz brzmi w trzcinie i Szczebrzeszyn z tego slynie" , "Grzegorz Brzeczyszczykiewicz" , 32 , "8cb0cb164f2554733ae02f5751b0e84a88fb385446e85a3991bdcdf1ea11795c" }, { NULL , 0 , NULL , NULL , 0 , NULL } cipher_pbkdf2_nss_sha1 ( const gchar * passphrase , const gchar * salt , guint iter_count , guint out_len ) SECAlgorithmID * algorithm = NULL ; PK11SymKey * symkey = NULL ; const SECItem * symkey_data = NULL ; SECItem salt_item , passphrase_item ; guchar * passphrase_buff , * salt_buff ; g_return_val_if_fail ( passphrase != NULL , NULL ); g_return_val_if_fail ( iter_count > 0 , NULL ); g_return_val_if_fail ( out_len > 0 , NULL ); slot = PK11_GetBestSlot ( PK11_AlgtagToMechanism ( SEC_OID_PKCS5_PBKDF2 ), purple_debug_error ( "cipher-test" , "NSS: couldn't get slot: " salt_buff = ( guchar * ) g_strdup ( salt ? salt : "" ); salt_item . type = siBuffer ; salt_item . data = salt_buff ; salt_item . len = salt ? strlen ( salt ) : 0 ; algorithm = PK11_CreatePBEV2AlgorithmID ( SEC_OID_PKCS5_PBKDF2 , SEC_OID_AES_256_CBC , SEC_OID_HMAC_SHA1 , out_len , iter_count , purple_debug_error ( "cipher-test" , "NSS: couldn't create " "algorithm ID: %d \n " , PR_GetError ()); passphrase_buff = ( guchar * ) g_strdup ( passphrase ); passphrase_item . type = siBuffer ; passphrase_item . data = passphrase_buff ; passphrase_item . len = strlen ( passphrase ); symkey = PK11_PBEKeyGen ( slot , algorithm , & passphrase_item , PR_FALSE , purple_debug_error ( "cipher-test" , "NSS: Couldn't generate key: " SECOID_DestroyAlgorithmID ( algorithm , PR_TRUE ); if ( PK11_ExtractKeyValue ( symkey ) == SECSuccess ) symkey_data = PK11_GetKeyData ( symkey ); if ( symkey_data == NULL || symkey_data -> data == NULL ) { purple_debug_error ( "cipher-test" , "NSS: Couldn't extract key " "value: %d \n " , PR_GetError ()); SECOID_DestroyAlgorithmID ( algorithm , PR_TRUE ); if ( symkey_data -> len != out_len ) { purple_debug_error ( "cipher-test" , "NSS: Invalid key length: %d " "(should be %d) \n " , symkey_data -> len , out_len ); SECOID_DestroyAlgorithmID ( algorithm , PR_TRUE ); ret = purple_base16_encode ( symkey_data -> data , symkey_data -> len ); SECOID_DestroyAlgorithmID ( algorithm , PR_TRUE ); purple_debug_info ( "cipher-test" , "Running PBKDF2 tests \n " ); while ( ! fail && pbkdf2_tests [ i ]. answer ) { pbkdf2_test * test = & pbkdf2_tests [ i ]; gchar digest [ 2 * 32 + 1 + 10 ]; gchar * digest_nss = NULL ; gboolean ret , skip_nss = FALSE ; purple_debug_info ( "cipher-test" , "Test %02d: \n " , i ); purple_debug_info ( "cipher-test" , " \t Testing '%s' with salt:'%s' hash:%s iter_count:%d \n " , test -> passphrase , test -> salt , test -> hash , if ( ! strcmp ( test -> hash , "sha1" )) hash = purple_sha1_hash_new (); else if ( ! strcmp ( test -> hash , "sha256" )) hash = purple_sha256_hash_new (); cipher = purple_pbkdf2_cipher_new ( hash ); g_object_set ( G_OBJECT ( cipher ), "iter_count" , GUINT_TO_POINTER ( test -> iter_count ), NULL ); g_object_set ( G_OBJECT ( cipher ), "out_len" , GUINT_TO_POINTER ( test -> out_len ), NULL ); purple_cipher_set_salt ( cipher , ( const guchar * ) test -> salt , test -> salt ? strlen ( test -> salt ) : 0 ); purple_cipher_set_key ( cipher , ( const guchar * ) test -> passphrase , strlen ( test -> passphrase )); ret = purple_cipher_digest_to_str ( cipher , digest , sizeof ( digest )); purple_cipher_reset ( cipher ); purple_debug_info ( "cipher-test" , " \t failed \n " ); if ( g_strcmp0 ( test -> hash , "sha1" ) != 0 ) if ( test -> out_len != 16 && test -> out_len != 32 ) digest_nss = cipher_pbkdf2_nss_sha1 ( test -> passphrase , test -> salt , test -> iter_count , test -> out_len ); purple_debug_info ( "cipher-test" , " \t Got: %s \n " , digest ); purple_debug_info ( "cipher-test" , " \t Got from NSS: %s \n " , digest_nss ); purple_debug_info ( "cipher-test" , " \t Wanted: %s \n " , test -> answer ); if ( g_strcmp0 ( digest , test -> answer ) == 0 && ( skip_nss || g_strcmp0 ( digest , digest_nss ) == 0 )) { purple_debug_info ( "cipher-test" , " \t Test OK \n " ); purple_debug_info ( "cipher-test" , " \t wrong answer \n " ); purple_debug_info ( "cipher-test" , "PBKDF2 tests FAILED \n\n " ); purple_debug_info ( "cipher-test" , "PBKDF2 tests completed successfully \n\n " ); /************************************************************************** **************************************************************************/ { NULL , "000102030405060708090a0b0c0d0e0f" , "plaintext" , "152e5b950e5f28fafadee9e96fcc59c9" }, { NULL , "000102030405060708090a0b0c0d0e0f" , NULL , "954f64f2e4e86e9eee82d20216684899" }, { "01010101010101010101010101010101" , "000102030405060708090a0b0c0d0e0f" , NULL , "35d14e6d3e3a279cf01e343e34e7ded3" }, { "01010101010101010101010101010101" , "000102030405060708090a0b0c0d0e0f" , "plaintext" , "19d1996e8c098cf3c94bba5dcf5bc57e" }, { "01010101010101010101010101010101" , "000102030405060708090a0b0c0d0e0f1011121314151617" , "plaintext" , "e8fba0deae94f63fe72ae9b8ef128aed" }, { "01010101010101010101010101010101" , "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" , "plaintext" , "e2dc50f6c60b33ac3b5953b6503cb684" }, { "01010101010101010101010101010101" , "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" , "W Szczebrzeszynie chrzaszcz brzmi w trzcinie i Szczebrzeszyn z tego slynie" , "8fcc068964e3505f0c2fac61c24592e5c8a9582d3a3264217cf605e9fd1cb056e679e159c4ac3110e8ce6c76c6630d42658c566ba3750c0e6da385b3a9baaa8b3a735b4c1ecaacf58037c8c281e523d2" }, { NULL , NULL , NULL , NULL } purple_debug_info ( "cipher-test" , "Running AES tests \n " ); cipher = purple_aes_cipher_new (); purple_debug_error ( "cipher-test" , "AES cipher not found \n " ); while ( ! fail && aes_tests [ i ]. cipher ) { aes_test * test = & aes_tests [ i ]; guchar cipher_s [ 1024 ], decipher_s [ 1024 ]; ssize_t cipher_len , decipher_len ; gchar * cipher_b16 , * deciphered ; purple_debug_info ( "cipher-test" , "Test %02d: \n " , i ); purple_debug_info ( "cipher-test" , " \t Testing '%s' (%" G_GSIZE_FORMAT "bit) \n " , test -> plaintext ? test -> plaintext : "(null)" , strlen ( test -> key ) * 8 / 2 ); purple_cipher_reset ( cipher ); guchar * iv = purple_base16_decode ( test -> iv , & iv_size ); purple_cipher_set_iv ( cipher , iv , iv_size ); key = purple_base16_decode ( test -> key , & key_size ); purple_cipher_set_key ( cipher , key , key_size ); if ( purple_cipher_get_key_size ( cipher ) != key_size ) { purple_debug_info ( "cipher-test" , " \t invalid key size \n " ); cipher_len = purple_cipher_encrypt ( cipher , ( const guchar * )( test -> plaintext ? test -> plaintext : "" ), test -> plaintext ? ( strlen ( test -> plaintext ) + 1 ) : 0 , cipher_s , sizeof ( cipher_s )); purple_debug_info ( "cipher-test" , " \t encryption failed \n " ); cipher_b16 = purple_base16_encode ( cipher_s , cipher_len ); purple_debug_info ( "cipher-test" , " \t Got: %s \n " , cipher_b16 ); purple_debug_info ( "cipher-test" , " \t Wanted: %s \n " , test -> cipher ); if ( g_strcmp0 ( cipher_b16 , test -> cipher ) != 0 ) { purple_debug_info ( "cipher-test" , " \t encrypted data doesn't match \n " ); decipher_len = purple_cipher_decrypt ( cipher , cipher_s , cipher_len , decipher_s , sizeof ( decipher_s )); purple_debug_info ( "cipher-test" , " \t decryption failed \n " ); deciphered = ( decipher_len > 0 ) ? ( gchar * ) decipher_s : NULL ; if ( g_strcmp0 ( deciphered , test -> plaintext ) != 0 ) { purple_debug_info ( "cipher-test" , " \t decrypted data doesn't match \n " ); purple_debug_info ( "cipher-test" , " \t Test OK \n " ); purple_debug_info ( "cipher-test" , "AES tests FAILED \n\n " ); purple_debug_info ( "cipher-test" , "AES tests completed successfully \n\n " ); /************************************************************************** **************************************************************************/ plugin_load ( PurplePlugin * plugin ) { plugin_unload ( PurplePlugin * plugin ) { static PurplePluginInfo info = PURPLE_PLUGIN_STANDARD , /**< type */ NULL , /**< ui_requirement */ NULL , /**< dependencies */ PURPLE_PRIORITY_DEFAULT , /**< priority */ "core-cipher-test" , /**< id */ N_ ( "Cipher Test" ), /**< name */ DISPLAY_VERSION , /**< version */ N_ ( "Tests the ciphers that ship with libpurple." ), N_ ( "Tests the ciphers that ship with libpurple." ), "Gary Kramlich <amc_grim@users.sf.net>" , /**< author */ PURPLE_WEBSITE , /**< homepage */ plugin_load , /**< load */ plugin_unload , /**< unload */ init_plugin ( PurplePlugin * plugin ) { PURPLE_INIT_PLUGIN ( cipher_test , init_plugin , info )